]> git.openstreetmap.org Git - rails.git/blobdiff - vendor/assets/iD/iD.js
Merge pull request #5151 from AntonKhorev/no-history-and-export-buttons
[rails.git] / vendor / assets / iD / iD.js
index 5c78af37936db3fa522f2896e3d3b93d737ad62a..99da55a78cade58c292321df249b99133d9018a0 100644 (file)
@@ -5,7 +5,14 @@
   var __getOwnPropNames = Object.getOwnPropertyNames;
   var __getProtoOf = Object.getPrototypeOf;
   var __hasOwnProp = Object.prototype.hasOwnProperty;
-  var __commonJS = (cb, mod) => function __require() {
+  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
+  var __require = /* @__PURE__ */ ((x2) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x2, {
+    get: (a2, b2) => (typeof require !== "undefined" ? require : a2)[b2]
+  }) : x2)(function(x2) {
+    if (typeof require !== "undefined") return require.apply(this, arguments);
+    throw Error('Dynamic require of "' + x2 + '" is not supported');
+  });
+  var __commonJS = (cb, mod) => function __require2() {
     return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
   };
   var __export = (target, all) => {
     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
   ));
+  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
 
   // node_modules/diacritics/index.js
   var require_diacritics = __commonJS({
         }
       ];
       var diacriticsMap = {};
-      for (i2 = 0; i2 < replacementList.length; i2 += 1) {
-        chars = replacementList[i2].chars;
+      for (i3 = 0; i3 < replacementList.length; i3 += 1) {
+        chars = replacementList[i3].chars;
         for (j2 = 0; j2 < chars.length; j2 += 1) {
-          diacriticsMap[chars[j2]] = replacementList[i2].base;
+          diacriticsMap[chars[j2]] = replacementList[i3].base;
         }
       }
       var chars;
       var j2;
-      var i2;
-      function removeDiacritics2(str2) {
-        return str2.replace(/[^\u0000-\u007e]/g, function(c) {
-          return diacriticsMap[c] || c;
+      var i3;
+      function removeDiacritics2(str) {
+        return str.replace(/[^\u0000-\u007e]/g, function(c2) {
+          return diacriticsMap[c2] || c2;
         });
       }
       exports2.replacementList = replacementList;
     "node_modules/alif-toolkit/lib/isArabic.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.isArabic = isArabic;
+      exports2.isMath = isMath;
       var arabicBlocks = [
         [1536, 1791],
+        // Arabic https://www.unicode.org/charts/PDF/U0600.pdf
         [1872, 1919],
+        // supplement https://www.unicode.org/charts/PDF/U0750.pdf
         [2208, 2303],
+        // Extended-A https://www.unicode.org/charts/PDF/U08A0.pdf
         [64336, 65023],
+        // Presentation Forms-A https://www.unicode.org/charts/PDF/UFB50.pdf
         [65136, 65279],
+        // Presentation Forms-B https://www.unicode.org/charts/PDF/UFE70.pdf
         [69216, 69247],
+        // Rumi numerals https://www.unicode.org/charts/PDF/U10E60.pdf
         [126064, 126143],
+        // Indic Siyaq numerals https://www.unicode.org/charts/PDF/U1EC70.pdf
         [126464, 126719]
+        // Mathematical Alphabetic symbols https://www.unicode.org/charts/PDF/U1EE00.pdf
       ];
       function isArabic(char) {
         if (char.length > 1) {
           throw new Error("isArabic works on only one-character strings");
         }
         let code = char.charCodeAt(0);
-        for (let i2 = 0; i2 < arabicBlocks.length; i2++) {
-          let block2 = arabicBlocks[i2];
+        for (let i3 = 0; i3 < arabicBlocks.length; i3++) {
+          let block2 = arabicBlocks[i3];
           if (code >= block2[0] && code <= block2[1]) {
             return true;
           }
         }
         return false;
       }
-      exports2.isArabic = isArabic;
       function isMath(char) {
         if (char.length > 2) {
           throw new Error("isMath works on only one-character strings");
         let code = char.charCodeAt(0);
         return code >= 1632 && code <= 1644 || code >= 1776 && code <= 1785;
       }
-      exports2.isMath = isMath;
     }
   });
 
     "node_modules/alif-toolkit/lib/reference.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.ligatureWordList = exports2.ligatureList = exports2.letterList = exports2.alefs = exports2.lams = exports2.lineBreakers = exports2.tashkeel = void 0;
       var unicode_arabic_1 = require_unicode_arabic();
       var unicode_ligatures_1 = require_unicode_ligatures();
       var letterList = Object.keys(unicode_arabic_1.default);
       var tashkeel = "\u0605\u0640\u0670\u0674\u06DF\u06E7\u06E8";
       exports2.tashkeel = tashkeel;
       function addToTashkeel(start2, finish) {
-        for (var i2 = start2; i2 <= finish; i2++) {
-          exports2.tashkeel = tashkeel += String.fromCharCode(i2);
+        for (var i3 = start2; i3 <= finish; i3++) {
+          exports2.tashkeel = tashkeel += String.fromCharCode(i3);
         }
       }
       addToTashkeel(1552, 1562);
       var lineBreakers = "\u0627\u0629\u0648\u06C0\u06CF\u06FD\u06FE\u076B\u076C\u0771\u0773\u0774\u0778\u0779\u08E2\u08B1\u08B2\u08B9";
       exports2.lineBreakers = lineBreakers;
       function addToLineBreakers(start2, finish) {
-        for (var i2 = start2; i2 <= finish; i2++) {
-          exports2.lineBreakers = lineBreakers += String.fromCharCode(i2);
+        for (var i3 = start2; i3 <= finish; i3++) {
+          exports2.lineBreakers = lineBreakers += String.fromCharCode(i3);
         }
       }
       addToLineBreakers(1536, 1567);
     "node_modules/alif-toolkit/lib/GlyphSplitter.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.GlyphSplitter = GlyphSplitter;
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function GlyphSplitter(word) {
         let letters = [];
         let lastLetter = "";
         word.split("").forEach((letter) => {
-          if (isArabic_1.isArabic(letter)) {
+          if ((0, isArabic_1.isArabic)(letter)) {
             if (reference_1.tashkeel.indexOf(letter) > -1) {
               letters[letters.length - 1] += letter;
             } else if (lastLetter.length && (reference_1.lams.indexOf(lastLetter) === 0 && reference_1.alefs.indexOf(letter) > -1 || reference_1.lams.indexOf(lastLetter) > 0 && reference_1.alefs.indexOf(letter) === 0)) {
         });
         return letters;
       }
-      exports2.GlyphSplitter = GlyphSplitter;
     }
   });
 
     "node_modules/alif-toolkit/lib/BaselineSplitter.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.BaselineSplitter = BaselineSplitter;
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function BaselineSplitter(word) {
         let letters = [];
         let lastLetter = "";
         word.split("").forEach((letter) => {
-          if (isArabic_1.isArabic(letter) && isArabic_1.isArabic(lastLetter)) {
+          if ((0, isArabic_1.isArabic)(letter) && (0, isArabic_1.isArabic)(lastLetter)) {
             if (lastLetter.length && reference_1.tashkeel.indexOf(letter) > -1) {
               letters[letters.length - 1] += letter;
             } else if (reference_1.lineBreakers.indexOf(lastLetter) > -1) {
         });
         return letters;
       }
-      exports2.BaselineSplitter = BaselineSplitter;
     }
   });
 
     "node_modules/alif-toolkit/lib/Normalization.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.Normal = Normal;
       var unicode_arabic_1 = require_unicode_arabic();
       var unicode_ligatures_1 = require_unicode_ligatures();
       var isArabic_1 = require_isArabic();
         }
         let returnable = "";
         word.split("").forEach((letter) => {
-          if (!isArabic_1.isArabic(letter)) {
+          if (!(0, isArabic_1.isArabic)(letter)) {
             returnable += letter;
             return;
           }
-          for (let w = 0; w < reference_1.letterList.length; w++) {
-            let letterForms = unicode_arabic_1.default[reference_1.letterList[w]];
+          for (let w2 = 0; w2 < reference_1.letterList.length; w2++) {
+            let letterForms = unicode_arabic_1.default[reference_1.letterList[w2]];
             let versions = Object.keys(letterForms);
-            for (let v = 0; v < versions.length; v++) {
-              let localVersion = letterForms[versions[v]];
+            for (let v2 = 0; v2 < versions.length; v2++) {
+              let localVersion = letterForms[versions[v2]];
               if (typeof localVersion === "object" && typeof localVersion.indexOf === "undefined") {
                 let embeddedForms = Object.keys(localVersion);
                 for (let ef = 0; ef < embeddedForms.length; ef++) {
                   }
                 }
               } else if (localVersion === letter) {
-                if (breakPresentationForm && letterForms["normal"] && ["isolated", "initial", "medial", "final"].indexOf(versions[v]) > -1) {
+                if (breakPresentationForm && letterForms["normal"] && ["isolated", "initial", "medial", "final"].indexOf(versions[v2]) > -1) {
                   if (typeof letterForms["normal"] === "object") {
                     returnable += letterForms["normal"][0];
                   } else {
         });
         return returnable;
       }
-      exports2.Normal = Normal;
     }
   });
 
     "node_modules/alif-toolkit/lib/CharShaper.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.CharShaper = CharShaper;
       var unicode_arabic_1 = require_unicode_arabic();
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function CharShaper(letter, form) {
-        if (!isArabic_1.isArabic(letter)) {
+        if (!(0, isArabic_1.isArabic)(letter)) {
           throw new Error("Not Arabic");
         }
         if (letter === "\u0621") {
           return "\u0621";
         }
-        for (let w = 0; w < reference_1.letterList.length; w++) {
-          let letterForms = unicode_arabic_1.default[reference_1.letterList[w]];
+        for (let w2 = 0; w2 < reference_1.letterList.length; w2++) {
+          let letterForms = unicode_arabic_1.default[reference_1.letterList[w2]];
           let versions = Object.keys(letterForms);
-          for (let v = 0; v < versions.length; v++) {
-            let localVersion = letterForms[versions[v]];
+          for (let v2 = 0; v2 < versions.length; v2++) {
+            let localVersion = letterForms[versions[v2]];
             if (localVersion === letter || typeof localVersion === "object" && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
               if (versions.indexOf(form) > -1) {
                 return letterForms[form];
           }
         }
       }
-      exports2.CharShaper = CharShaper;
     }
   });
 
     "node_modules/alif-toolkit/lib/WordShaper.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.WordShaper = WordShaper2;
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       var CharShaper_1 = require_CharShaper();
       function WordShaper2(word) {
         let state = "initial";
         let output = "";
-        for (let w = 0; w < word.length; w++) {
+        for (let w2 = 0; w2 < word.length; w2++) {
           let nextLetter = " ";
-          for (let nxw = w + 1; nxw < word.length; nxw++) {
-            if (!isArabic_1.isArabic(word[nxw])) {
+          for (let nxw = w2 + 1; nxw < word.length; nxw++) {
+            if (!(0, isArabic_1.isArabic)(word[nxw])) {
               break;
             }
             if (reference_1.tashkeel.indexOf(word[nxw]) === -1) {
               break;
             }
           }
-          if (!isArabic_1.isArabic(word[w]) || isArabic_1.isMath(word[w])) {
-            output += word[w];
+          if (!(0, isArabic_1.isArabic)(word[w2]) || (0, isArabic_1.isMath)(word[w2])) {
+            output += word[w2];
             state = "initial";
-          } else if (reference_1.tashkeel.indexOf(word[w]) > -1) {
-            output += word[w];
-          } else if (nextLetter === " " || reference_1.lineBreakers.indexOf(word[w]) > -1) {
-            output += CharShaper_1.CharShaper(word[w], state === "initial" ? "isolated" : "final");
+          } else if (reference_1.tashkeel.indexOf(word[w2]) > -1) {
+            output += word[w2];
+          } else if (nextLetter === " " || reference_1.lineBreakers.indexOf(word[w2]) > -1) {
+            output += (0, CharShaper_1.CharShaper)(word[w2], state === "initial" ? "isolated" : "final");
             state = "initial";
-          } else if (reference_1.lams.indexOf(word[w]) > -1 && reference_1.alefs.indexOf(nextLetter) > -1) {
-            output += unicode_ligatures_1.default[word[w] + nextLetter][state === "initial" ? "isolated" : "final"];
-            while (word[w] !== nextLetter) {
-              w++;
+          } else if (reference_1.lams.indexOf(word[w2]) > -1 && reference_1.alefs.indexOf(nextLetter) > -1) {
+            output += unicode_ligatures_1.default[word[w2] + nextLetter][state === "initial" ? "isolated" : "final"];
+            while (word[w2] !== nextLetter) {
+              w2++;
             }
             state = "initial";
           } else {
-            output += CharShaper_1.CharShaper(word[w], state);
+            output += (0, CharShaper_1.CharShaper)(word[w2], state);
             state = "medial";
           }
         }
         return output;
       }
-      exports2.WordShaper = WordShaper2;
     }
   });
 
     "node_modules/alif-toolkit/lib/ParentLetter.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.ParentLetter = ParentLetter;
+      exports2.GrandparentLetter = GrandparentLetter;
       var unicode_arabic_1 = require_unicode_arabic();
       var isArabic_1 = require_isArabic();
       var reference_1 = require_reference();
       function ParentLetter(letter) {
-        if (!isArabic_1.isArabic(letter)) {
+        if (!(0, isArabic_1.isArabic)(letter)) {
           throw new Error("Not an Arabic letter");
         }
-        for (let w = 0; w < reference_1.letterList.length; w++) {
-          let letterForms = unicode_arabic_1.default[reference_1.letterList[w]];
+        for (let w2 = 0; w2 < reference_1.letterList.length; w2++) {
+          let letterForms = unicode_arabic_1.default[reference_1.letterList[w2]];
           let versions = Object.keys(letterForms);
-          for (let v = 0; v < versions.length; v++) {
-            let localVersion = letterForms[versions[v]];
+          for (let v2 = 0; v2 < versions.length; v2++) {
+            let localVersion = letterForms[versions[v2]];
             if (typeof localVersion === "object" && typeof localVersion.indexOf === "undefined") {
               let embeddedForms = Object.keys(localVersion);
               for (let ef = 0; ef < embeddedForms.length; ef++) {
           return null;
         }
       }
-      exports2.ParentLetter = ParentLetter;
       function GrandparentLetter(letter) {
-        if (!isArabic_1.isArabic(letter)) {
+        if (!(0, isArabic_1.isArabic)(letter)) {
           throw new Error("Not an Arabic letter");
         }
-        for (let w = 0; w < reference_1.letterList.length; w++) {
-          let letterForms = unicode_arabic_1.default[reference_1.letterList[w]];
+        for (let w2 = 0; w2 < reference_1.letterList.length; w2++) {
+          let letterForms = unicode_arabic_1.default[reference_1.letterList[w2]];
           let versions = Object.keys(letterForms);
-          for (let v = 0; v < versions.length; v++) {
-            let localVersion = letterForms[versions[v]];
+          for (let v2 = 0; v2 < versions.length; v2++) {
+            let localVersion = letterForms[versions[v2]];
             if (typeof localVersion === "object" && typeof localVersion.indexOf === "undefined") {
               let embeddedForms = Object.keys(localVersion);
               for (let ef = 0; ef < embeddedForms.length; ef++) {
           return null;
         }
       }
-      exports2.GrandparentLetter = GrandparentLetter;
     }
   });
 
     "node_modules/alif-toolkit/lib/index.js"(exports2) {
       "use strict";
       Object.defineProperty(exports2, "__esModule", { value: true });
+      exports2.GrandparentLetter = exports2.ParentLetter = exports2.WordShaper = exports2.CharShaper = exports2.Normal = exports2.BaselineSplitter = exports2.GlyphSplitter = exports2.isArabic = void 0;
       var isArabic_1 = require_isArabic();
-      exports2.isArabic = isArabic_1.isArabic;
+      Object.defineProperty(exports2, "isArabic", { enumerable: true, get: function() {
+        return isArabic_1.isArabic;
+      } });
       var GlyphSplitter_1 = require_GlyphSplitter();
-      exports2.GlyphSplitter = GlyphSplitter_1.GlyphSplitter;
+      Object.defineProperty(exports2, "GlyphSplitter", { enumerable: true, get: function() {
+        return GlyphSplitter_1.GlyphSplitter;
+      } });
       var BaselineSplitter_1 = require_BaselineSplitter();
-      exports2.BaselineSplitter = BaselineSplitter_1.BaselineSplitter;
+      Object.defineProperty(exports2, "BaselineSplitter", { enumerable: true, get: function() {
+        return BaselineSplitter_1.BaselineSplitter;
+      } });
       var Normalization_1 = require_Normalization();
-      exports2.Normal = Normalization_1.Normal;
+      Object.defineProperty(exports2, "Normal", { enumerable: true, get: function() {
+        return Normalization_1.Normal;
+      } });
       var CharShaper_1 = require_CharShaper();
-      exports2.CharShaper = CharShaper_1.CharShaper;
+      Object.defineProperty(exports2, "CharShaper", { enumerable: true, get: function() {
+        return CharShaper_1.CharShaper;
+      } });
       var WordShaper_1 = require_WordShaper();
-      exports2.WordShaper = WordShaper_1.WordShaper;
+      Object.defineProperty(exports2, "WordShaper", { enumerable: true, get: function() {
+        return WordShaper_1.WordShaper;
+      } });
       var ParentLetter_1 = require_ParentLetter();
-      exports2.ParentLetter = ParentLetter_1.ParentLetter;
-      exports2.GrandparentLetter = ParentLetter_1.GrandparentLetter;
+      Object.defineProperty(exports2, "ParentLetter", { enumerable: true, get: function() {
+        return ParentLetter_1.ParentLetter;
+      } });
+      Object.defineProperty(exports2, "GrandparentLetter", { enumerable: true, get: function() {
+        return ParentLetter_1.GrandparentLetter;
+      } });
     }
   });
 
     "node_modules/vparse/index.js"(exports2, module2) {
       (function(window2) {
         "use strict";
-        function parseVersion3(v) {
-          var m = v.replace(/[^0-9.]/g, "").match(/[0-9]*\.|[0-9]+/g) || [];
-          v = {
-            major: +m[0] || 0,
-            minor: +m[1] || 0,
-            patch: +m[2] || 0,
-            build: +m[3] || 0
+        function parseVersion3(v2) {
+          var m2 = v2.replace(/[^0-9.]/g, "").match(/[0-9]*\.|[0-9]+/g) || [];
+          v2 = {
+            major: +m2[0] || 0,
+            minor: +m2[1] || 0,
+            patch: +m2[2] || 0,
+            build: +m2[3] || 0
           };
-          v.isEmpty = !v.major && !v.minor && !v.patch && !v.build;
-          v.parsed = [v.major, v.minor, v.patch, v.build];
-          v.text = v.parsed.join(".");
-          v.compare = compare;
-          return v;
+          v2.isEmpty = !v2.major && !v2.minor && !v2.patch && !v2.build;
+          v2.parsed = [v2.major, v2.minor, v2.patch, v2.build];
+          v2.text = v2.parsed.join(".");
+          v2.compare = compare2;
+          return v2;
         }
-        function compare(v) {
-          if (typeof v === "string") {
-            v = parseVersion3(v);
+        function compare2(v2) {
+          if (typeof v2 === "string") {
+            v2 = parseVersion3(v2);
           }
-          for (var i2 = 0; i2 < 4; i2++) {
-            if (this.parsed[i2] !== v.parsed[i2]) {
-              return this.parsed[i2] > v.parsed[i2] ? 1 : -1;
+          for (var i3 = 0; i3 < 4; i3++) {
+            if (this.parsed[i3] !== v2.parsed[i3]) {
+              return this.parsed[i3] > v2.parsed[i3] ? 1 : -1;
             }
           }
           return 0;
   // node_modules/which-polygon/node_modules/quickselect/quickselect.js
   var require_quickselect = __commonJS({
     "node_modules/which-polygon/node_modules/quickselect/quickselect.js"(exports2, module2) {
-      (function(global3, factory) {
-        typeof exports2 === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global3.quickselect = factory();
+      (function(global2, factory) {
+        typeof exports2 === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global2.quickselect = factory();
       })(exports2, function() {
         "use strict";
-        function quickselect2(arr, k, left, right, compare) {
-          quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
+        function quickselect3(arr, k2, left, right, compare2) {
+          quickselectStep2(arr, k2, left || 0, right || arr.length - 1, compare2 || defaultCompare2);
         }
-        function quickselectStep(arr, k, left, right, compare) {
+        function quickselectStep2(arr, k2, left, right, compare2) {
           while (right > left) {
             if (right - left > 600) {
-              var n2 = right - left + 1;
-              var m = k - left + 1;
-              var z = Math.log(n2);
-              var s = 0.5 * Math.exp(2 * z / 3);
-              var sd = 0.5 * Math.sqrt(z * s * (n2 - s) / n2) * (m - n2 / 2 < 0 ? -1 : 1);
-              var newLeft = Math.max(left, Math.floor(k - m * s / n2 + sd));
-              var newRight = Math.min(right, Math.floor(k + (n2 - m) * s / n2 + sd));
-              quickselectStep(arr, k, newLeft, newRight, compare);
-            }
-            var t = arr[k];
-            var i2 = left;
+              var n3 = right - left + 1;
+              var m2 = k2 - left + 1;
+              var z2 = Math.log(n3);
+              var s2 = 0.5 * Math.exp(2 * z2 / 3);
+              var sd = 0.5 * Math.sqrt(z2 * s2 * (n3 - s2) / n3) * (m2 - n3 / 2 < 0 ? -1 : 1);
+              var newLeft = Math.max(left, Math.floor(k2 - m2 * s2 / n3 + sd));
+              var newRight = Math.min(right, Math.floor(k2 + (n3 - m2) * s2 / n3 + sd));
+              quickselectStep2(arr, k2, newLeft, newRight, compare2);
+            }
+            var t2 = arr[k2];
+            var i3 = left;
             var j2 = right;
-            swap2(arr, left, k);
-            if (compare(arr[right], t) > 0)
-              swap2(arr, left, right);
-            while (i2 < j2) {
-              swap2(arr, i2, j2);
-              i2++;
+            swap3(arr, left, k2);
+            if (compare2(arr[right], t2) > 0) swap3(arr, left, right);
+            while (i3 < j2) {
+              swap3(arr, i3, j2);
+              i3++;
               j2--;
-              while (compare(arr[i2], t) < 0)
-                i2++;
-              while (compare(arr[j2], t) > 0)
-                j2--;
+              while (compare2(arr[i3], t2) < 0) i3++;
+              while (compare2(arr[j2], t2) > 0) j2--;
             }
-            if (compare(arr[left], t) === 0)
-              swap2(arr, left, j2);
+            if (compare2(arr[left], t2) === 0) swap3(arr, left, j2);
             else {
               j2++;
-              swap2(arr, j2, right);
+              swap3(arr, j2, right);
             }
-            if (j2 <= k)
-              left = j2 + 1;
-            if (k <= j2)
-              right = j2 - 1;
+            if (j2 <= k2) left = j2 + 1;
+            if (k2 <= j2) right = j2 - 1;
           }
         }
-        function swap2(arr, i2, j2) {
-          var tmp = arr[i2];
-          arr[i2] = arr[j2];
+        function swap3(arr, i3, j2) {
+          var tmp = arr[i3];
+          arr[i3] = arr[j2];
           arr[j2] = tmp;
         }
-        function defaultCompare(a, b) {
-          return a < b ? -1 : a > b ? 1 : 0;
+        function defaultCompare2(a2, b2) {
+          return a2 < b2 ? -1 : a2 > b2 ? 1 : 0;
         }
-        return quickselect2;
+        return quickselect3;
       });
     }
   });
       "use strict";
       module2.exports = rbush;
       module2.exports.default = rbush;
-      var quickselect2 = require_quickselect();
+      var quickselect3 = require_quickselect();
       function rbush(maxEntries, format2) {
-        if (!(this instanceof rbush))
-          return new rbush(maxEntries, format2);
+        if (!(this instanceof rbush)) return new rbush(maxEntries, format2);
         this._maxEntries = Math.max(4, maxEntries || 9);
         this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
         if (format2) {
         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))
-            return result;
-          var nodesToSearch = [], i2, len, child, childBBox;
+          if (!intersects2(bbox2, node)) return result;
+          var nodesToSearch = [], i3, len, child, childBBox;
           while (node) {
-            for (i2 = 0, len = node.children.length; i2 < len; i2++) {
-              child = node.children[i2];
+            for (i3 = 0, len = node.children.length; i3 < len; i3++) {
+              child = node.children[i3];
               childBBox = node.leaf ? toBBox(child) : child;
-              if (intersects(bbox, childBBox)) {
-                if (node.leaf)
-                  result.push(child);
-                else if (contains(bbox, childBBox))
-                  this._all(child, result);
-                else
-                  nodesToSearch.push(child);
+              if (intersects2(bbox2, childBBox)) {
+                if (node.leaf) result.push(child);
+                else if (contains2(bbox2, childBBox)) this._all(child, result);
+                else nodesToSearch.push(child);
               }
             }
             node = nodesToSearch.pop();
           }
           return result;
         },
-        collides: function(bbox) {
+        collides: function(bbox2) {
           var node = this.data, toBBox = this.toBBox;
-          if (!intersects(bbox, node))
-            return false;
-          var nodesToSearch = [], i2, len, child, childBBox;
+          if (!intersects2(bbox2, node)) return false;
+          var nodesToSearch = [], i3, len, child, childBBox;
           while (node) {
-            for (i2 = 0, len = node.children.length; i2 < len; i2++) {
-              child = node.children[i2];
+            for (i3 = 0, len = node.children.length; i3 < len; i3++) {
+              child = node.children[i3];
               childBBox = node.leaf ? toBBox(child) : child;
-              if (intersects(bbox, childBBox)) {
-                if (node.leaf || contains(bbox, childBBox))
-                  return true;
+              if (intersects2(bbox2, childBBox)) {
+                if (node.leaf || contains2(bbox2, childBBox)) return true;
                 nodesToSearch.push(child);
               }
             }
           return false;
         },
         load: function(data) {
-          if (!(data && data.length))
-            return this;
+          if (!(data && data.length)) return this;
           if (data.length < this._minEntries) {
-            for (var i2 = 0, len = data.length; i2 < len; i2++) {
-              this.insert(data[i2]);
+            for (var i3 = 0, len = data.length; i3 < len; i3++) {
+              this.insert(data[i3]);
             }
             return this;
           }
           return this;
         },
         insert: function(item) {
-          if (item)
-            this._insert(item, this.data.height - 1);
+          if (item) this._insert(item, this.data.height - 1);
           return this;
         },
         clear: function() {
-          this.data = createNode([]);
+          this.data = createNode2([]);
           return this;
         },
         remove: function(item, equalsFn) {
-          if (!item)
-            return this;
-          var node = this.data, bbox = this.toBBox(item), path = [], indexes = [], i2, parent, index, goingUp;
+          if (!item) return this;
+          var node = this.data, bbox2 = this.toBBox(item), path = [], indexes = [], i3, parent, index, goingUp;
           while (node || path.length) {
             if (!node) {
               node = path.pop();
               parent = path[path.length - 1];
-              i2 = indexes.pop();
+              i3 = indexes.pop();
               goingUp = true;
             }
             if (node.leaf) {
-              index = findItem(item, node.children, equalsFn);
+              index = findItem2(item, node.children, equalsFn);
               if (index !== -1) {
                 node.children.splice(index, 1);
                 path.push(node);
                 return this;
               }
             }
-            if (!goingUp && !node.leaf && contains(node, bbox)) {
+            if (!goingUp && !node.leaf && contains2(node, bbox2)) {
               path.push(node);
-              indexes.push(i2);
-              i2 = 0;
+              indexes.push(i3);
+              i3 = 0;
               parent = node;
               node = node.children[0];
             } else if (parent) {
-              i2++;
-              node = parent.children[i2];
+              i3++;
+              node = parent.children[i3];
               goingUp = false;
-            } else
-              node = null;
+            } else node = null;
           }
           return this;
         },
         toBBox: function(item) {
           return item;
         },
-        compareMinX: compareNodeMinX,
-        compareMinY: compareNodeMinY,
+        compareMinX: compareNodeMinX2,
+        compareMinY: compareNodeMinY2,
         toJSON: function() {
           return this.data;
         },
         _all: function(node, result) {
           var nodesToSearch = [];
           while (node) {
-            if (node.leaf)
-              result.push.apply(result, node.children);
-            else
-              nodesToSearch.push.apply(nodesToSearch, node.children);
+            if (node.leaf) result.push.apply(result, node.children);
+            else nodesToSearch.push.apply(nodesToSearch, node.children);
             node = nodesToSearch.pop();
           }
           return result;
         },
         _build: function(items, left, right, height) {
-          var N = right - left + 1, M = this._maxEntries, node;
-          if (N <= M) {
-            node = createNode(items.slice(left, right + 1));
-            calcBBox(node, this.toBBox);
+          var N2 = right - left + 1, M2 = this._maxEntries, node;
+          if (N2 <= M2) {
+            node = createNode2(items.slice(left, right + 1));
+            calcBBox2(node, this.toBBox);
             return node;
           }
           if (!height) {
-            height = Math.ceil(Math.log(N) / Math.log(M));
-            M = Math.ceil(N / Math.pow(M, height - 1));
+            height = Math.ceil(Math.log(N2) / Math.log(M2));
+            M2 = Math.ceil(N2 / Math.pow(M2, height - 1));
           }
-          node = createNode([]);
+          node = createNode2([]);
           node.leaf = false;
           node.height = height;
-          var N2 = Math.ceil(N / M), N1 = N2 * Math.ceil(Math.sqrt(M)), i2, j2, right2, right3;
-          multiSelect(items, left, right, N1, this.compareMinX);
-          for (i2 = left; i2 <= right; i2 += N1) {
-            right2 = Math.min(i2 + N1 - 1, right);
-            multiSelect(items, i2, right2, N2, this.compareMinY);
-            for (j2 = i2; j2 <= right2; j2 += N2) {
-              right3 = Math.min(j2 + N2 - 1, right2);
+          var N22 = Math.ceil(N2 / M2), N1 = N22 * Math.ceil(Math.sqrt(M2)), i3, j2, right2, right3;
+          multiSelect2(items, left, right, N1, this.compareMinX);
+          for (i3 = left; i3 <= right; i3 += N1) {
+            right2 = Math.min(i3 + N1 - 1, right);
+            multiSelect2(items, i3, right2, N22, this.compareMinY);
+            for (j2 = i3; j2 <= right2; j2 += N22) {
+              right3 = Math.min(j2 + N22 - 1, right2);
               node.children.push(this._build(items, j2, right3, height - 1));
             }
           }
-          calcBBox(node, this.toBBox);
+          calcBBox2(node, this.toBBox);
           return node;
         },
-        _chooseSubtree: function(bbox, node, level, path) {
-          var i2, len, child, targetNode, area, enlargement, minArea, minEnlargement;
+        _chooseSubtree: function(bbox2, node, level, path) {
+          var i3, len, child, targetNode, area, enlargement, minArea, minEnlargement;
           while (true) {
             path.push(node);
-            if (node.leaf || path.length - 1 === level)
-              break;
+            if (node.leaf || path.length - 1 === level) break;
             minArea = minEnlargement = Infinity;
-            for (i2 = 0, len = node.children.length; i2 < len; i2++) {
-              child = node.children[i2];
-              area = bboxArea(child);
-              enlargement = enlargedArea(bbox, child) - area;
+            for (i3 = 0, len = node.children.length; i3 < len; i3++) {
+              child = node.children[i3];
+              area = bboxArea2(child);
+              enlargement = enlargedArea2(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);
+          extend3(node, bbox2);
           while (level >= 0) {
             if (insertPath[level].children.length > this._maxEntries) {
               this._split(insertPath, level);
               level--;
-            } else
-              break;
+            } 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);
-          var splitIndex = this._chooseSplitIndex(node, m, M);
-          var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
+          var node = insertPath[level], M2 = node.children.length, m2 = this._minEntries;
+          this._chooseSplitAxis(node, m2, M2);
+          var splitIndex = this._chooseSplitIndex(node, m2, M2);
+          var newNode = createNode2(node.children.splice(splitIndex, node.children.length - splitIndex));
           newNode.height = node.height;
           newNode.leaf = node.leaf;
-          calcBBox(node, this.toBBox);
-          calcBBox(newNode, this.toBBox);
-          if (level)
-            insertPath[level - 1].children.push(newNode);
-          else
-            this._splitRoot(node, newNode);
+          calcBBox2(node, this.toBBox);
+          calcBBox2(newNode, this.toBBox);
+          if (level) insertPath[level - 1].children.push(newNode);
+          else this._splitRoot(node, newNode);
         },
         _splitRoot: function(node, newNode) {
-          this.data = createNode([node, newNode]);
+          this.data = createNode2([node, newNode]);
           this.data.height = node.height + 1;
           this.data.leaf = false;
-          calcBBox(this.data, this.toBBox);
+          calcBBox2(this.data, this.toBBox);
         },
-        _chooseSplitIndex: function(node, m, M) {
-          var i2, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
+        _chooseSplitIndex: function(node, m2, M2) {
+          var i3, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
           minOverlap = minArea = Infinity;
-          for (i2 = m; i2 <= M - m; i2++) {
-            bbox1 = distBBox(node, 0, i2, this.toBBox);
-            bbox2 = distBBox(node, i2, M, this.toBBox);
-            overlap = intersectionArea(bbox1, bbox2);
-            area = bboxArea(bbox1) + bboxArea(bbox2);
+          for (i3 = m2; i3 <= M2 - m2; i3++) {
+            bbox1 = distBBox2(node, 0, i3, this.toBBox);
+            bbox2 = distBBox2(node, i3, M2, this.toBBox);
+            overlap = intersectionArea2(bbox1, bbox2);
+            area = bboxArea2(bbox1) + bboxArea2(bbox2);
             if (overlap < minOverlap) {
               minOverlap = overlap;
-              index = i2;
+              index = i3;
               minArea = area < minArea ? area : minArea;
             } else if (overlap === minOverlap) {
               if (area < minArea) {
                 minArea = area;
-                index = i2;
+                index = i3;
               }
             }
           }
           return index;
         },
-        _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);
-        },
-        _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;
-          for (i2 = m; i2 < M - m; i2++) {
-            child = node.children[i2];
-            extend2(leftBBox, node.leaf ? toBBox(child) : child);
-            margin += bboxMargin(leftBBox);
-          }
-          for (i2 = M - m - 1; i2 >= m; i2--) {
-            child = node.children[i2];
-            extend2(rightBBox, node.leaf ? toBBox(child) : child);
-            margin += bboxMargin(rightBBox);
+        // sorts node children by the best axis for split
+        _chooseSplitAxis: function(node, m2, M2) {
+          var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX2, compareMinY = node.leaf ? this.compareMinY : compareNodeMinY2, xMargin = this._allDistMargin(node, m2, M2, compareMinX), yMargin = this._allDistMargin(node, m2, M2, compareMinY);
+          if (xMargin < yMargin) node.children.sort(compareMinX);
+        },
+        // total margin of all possible split distributions where each node is at least m full
+        _allDistMargin: function(node, m2, M2, compare2) {
+          node.children.sort(compare2);
+          var toBBox = this.toBBox, leftBBox = distBBox2(node, 0, m2, toBBox), rightBBox = distBBox2(node, M2 - m2, M2, toBBox), margin = bboxMargin2(leftBBox) + bboxMargin2(rightBBox), i3, child;
+          for (i3 = m2; i3 < M2 - m2; i3++) {
+            child = node.children[i3];
+            extend3(leftBBox, node.leaf ? toBBox(child) : child);
+            margin += bboxMargin2(leftBBox);
+          }
+          for (i3 = M2 - m2 - 1; i3 >= m2; i3--) {
+            child = node.children[i3];
+            extend3(rightBBox, node.leaf ? toBBox(child) : child);
+            margin += bboxMargin2(rightBBox);
           }
           return margin;
         },
-        _adjustParentBBoxes: function(bbox, path, level) {
-          for (var i2 = level; i2 >= 0; i2--) {
-            extend2(path[i2], bbox);
+        _adjustParentBBoxes: function(bbox2, path, level) {
+          for (var i3 = level; i3 >= 0; i3--) {
+            extend3(path[i3], bbox2);
           }
         },
         _condense: function(path) {
-          for (var i2 = path.length - 1, siblings; i2 >= 0; i2--) {
-            if (path[i2].children.length === 0) {
-              if (i2 > 0) {
-                siblings = path[i2 - 1].children;
-                siblings.splice(siblings.indexOf(path[i2]), 1);
-              } else
-                this.clear();
-            } else
-              calcBBox(path[i2], this.toBBox);
+          for (var i3 = path.length - 1, siblings; i3 >= 0; i3--) {
+            if (path[i3].children.length === 0) {
+              if (i3 > 0) {
+                siblings = path[i3 - 1].children;
+                siblings.splice(siblings.indexOf(path[i3]), 1);
+              } else this.clear();
+            } else calcBBox2(path[i3], this.toBBox);
           }
         },
         _initFormat: function(format2) {
           );
         }
       };
-      function findItem(item, items, equalsFn) {
-        if (!equalsFn)
-          return items.indexOf(item);
-        for (var i2 = 0; i2 < items.length; i2++) {
-          if (equalsFn(item, items[i2]))
-            return i2;
+      function findItem2(item, items, equalsFn) {
+        if (!equalsFn) return items.indexOf(item);
+        for (var i3 = 0; i3 < items.length; i3++) {
+          if (equalsFn(item, items[i3])) return i3;
         }
         return -1;
       }
-      function calcBBox(node, toBBox) {
-        distBBox(node, 0, node.children.length, toBBox, node);
+      function calcBBox2(node, toBBox) {
+        distBBox2(node, 0, node.children.length, toBBox, node);
       }
-      function distBBox(node, k, p, toBBox, destNode) {
-        if (!destNode)
-          destNode = createNode(null);
+      function distBBox2(node, k2, p2, toBBox, destNode) {
+        if (!destNode) destNode = createNode2(null);
         destNode.minX = Infinity;
         destNode.minY = Infinity;
         destNode.maxX = -Infinity;
         destNode.maxY = -Infinity;
-        for (var i2 = k, child; i2 < p; i2++) {
-          child = node.children[i2];
-          extend2(destNode, node.leaf ? toBBox(child) : child);
+        for (var i3 = k2, child; i3 < p2; i3++) {
+          child = node.children[i3];
+          extend3(destNode, node.leaf ? toBBox(child) : child);
         }
         return destNode;
       }
-      function extend2(a, b) {
-        a.minX = Math.min(a.minX, b.minX);
-        a.minY = Math.min(a.minY, b.minY);
-        a.maxX = Math.max(a.maxX, b.maxX);
-        a.maxY = Math.max(a.maxY, b.maxY);
-        return a;
+      function extend3(a2, b2) {
+        a2.minX = Math.min(a2.minX, b2.minX);
+        a2.minY = Math.min(a2.minY, b2.minY);
+        a2.maxX = Math.max(a2.maxX, b2.maxX);
+        a2.maxY = Math.max(a2.maxY, b2.maxY);
+        return a2;
       }
-      function compareNodeMinX(a, b) {
-        return a.minX - b.minX;
+      function compareNodeMinX2(a2, b2) {
+        return a2.minX - b2.minX;
       }
-      function compareNodeMinY(a, b) {
-        return a.minY - b.minY;
+      function compareNodeMinY2(a2, b2) {
+        return a2.minY - b2.minY;
       }
-      function bboxArea(a) {
-        return (a.maxX - a.minX) * (a.maxY - a.minY);
+      function bboxArea2(a2) {
+        return (a2.maxX - a2.minX) * (a2.maxY - a2.minY);
       }
-      function bboxMargin(a) {
-        return a.maxX - a.minX + (a.maxY - a.minY);
+      function bboxMargin2(a2) {
+        return a2.maxX - a2.minX + (a2.maxY - a2.minY);
       }
-      function enlargedArea(a, b) {
-        return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
+      function enlargedArea2(a2, b2) {
+        return (Math.max(b2.maxX, a2.maxX) - Math.min(b2.minX, a2.minX)) * (Math.max(b2.maxY, a2.maxY) - Math.min(b2.minY, a2.minY));
       }
-      function intersectionArea(a, b) {
-        var minX = Math.max(a.minX, b.minX), minY = Math.max(a.minY, b.minY), maxX = Math.min(a.maxX, b.maxX), maxY = Math.min(a.maxY, b.maxY);
+      function intersectionArea2(a2, b2) {
+        var minX = Math.max(a2.minX, b2.minX), minY = Math.max(a2.minY, b2.minY), maxX = Math.min(a2.maxX, b2.maxX), maxY = Math.min(a2.maxY, b2.maxY);
         return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
       }
-      function contains(a, b) {
-        return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
+      function contains2(a2, b2) {
+        return a2.minX <= b2.minX && a2.minY <= b2.minY && b2.maxX <= a2.maxX && b2.maxY <= a2.maxY;
       }
-      function intersects(a, b) {
-        return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
+      function intersects2(a2, b2) {
+        return b2.minX <= a2.maxX && b2.minY <= a2.maxY && b2.maxX >= a2.minX && b2.maxY >= a2.minY;
       }
-      function createNode(children2) {
+      function createNode2(children2) {
         return {
           children: children2,
           height: 1,
           maxY: -Infinity
         };
       }
-      function multiSelect(arr, left, right, n2, compare) {
+      function multiSelect2(arr, left, right, n3, compare2) {
         var stack = [left, right], mid;
         while (stack.length) {
           right = stack.pop();
           left = stack.pop();
-          if (right - left <= n2)
-            continue;
-          mid = left + Math.ceil((right - left) / n2 / 2) * n2;
-          quickselect2(arr, mid, left, right, compare);
+          if (right - left <= n3) continue;
+          mid = left + Math.ceil((right - left) / n3 / 2) * n3;
+          quickselect3(arr, mid, left, right, compare2);
           stack.push(left, mid, mid, right);
         }
       }
       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;
-        if (!result)
-          result = [];
-        for (i2 = 1; i2 < len; i2++) {
-          a = points[i2 - 1];
-          b = points[i2];
-          codeB = lastCode = bitCode2(b, bbox);
+      function lineclip2(points, bbox2, result) {
+        var len = points.length, codeA = bitCode2(points[0], bbox2), part = [], i3, a2, b2, codeB, lastCode;
+        if (!result) result = [];
+        for (i3 = 1; i3 < len; i3++) {
+          a2 = points[i3 - 1];
+          b2 = points[i3];
+          codeB = lastCode = bitCode2(b2, bbox2);
           while (true) {
             if (!(codeA | codeB)) {
-              part.push(a);
+              part.push(a2);
               if (codeB !== lastCode) {
-                part.push(b);
-                if (i2 < len - 1) {
+                part.push(b2);
+                if (i3 < len - 1) {
                   result.push(part);
                   part = [];
                 }
-              } else if (i2 === len - 1) {
-                part.push(b);
+              } else if (i3 === len - 1) {
+                part.push(b2);
               }
               break;
             } else if (codeA & codeB) {
               break;
             } else if (codeA) {
-              a = intersect2(a, b, codeA, bbox);
-              codeA = bitCode2(a, bbox);
+              a2 = intersect2(a2, b2, codeA, bbox2);
+              codeA = bitCode2(a2, bbox2);
             } else {
-              b = intersect2(a, b, codeB, bbox);
-              codeB = bitCode2(b, bbox);
+              b2 = intersect2(a2, b2, codeB, bbox2);
+              codeB = bitCode2(b2, bbox2);
             }
           }
           codeA = lastCode;
         }
-        if (part.length)
-          result.push(part);
+        if (part.length) result.push(part);
         return result;
       }
-      function polygonclip2(points, bbox) {
-        var result, edge, prev, prevInside, i2, p, inside;
+      function polygonclip2(points, bbox2) {
+        var result, edge, prev, prevInside, i3, p2, inside;
         for (edge = 1; edge <= 8; edge *= 2) {
           result = [];
           prev = points[points.length - 1];
-          prevInside = !(bitCode2(prev, bbox) & edge);
-          for (i2 = 0; i2 < points.length; i2++) {
-            p = points[i2];
-            inside = !(bitCode2(p, bbox) & edge);
-            if (inside !== prevInside)
-              result.push(intersect2(prev, p, edge, bbox));
-            if (inside)
-              result.push(p);
-            prev = p;
+          prevInside = !(bitCode2(prev, bbox2) & edge);
+          for (i3 = 0; i3 < points.length; i3++) {
+            p2 = points[i3];
+            inside = !(bitCode2(p2, bbox2) & edge);
+            if (inside !== prevInside) result.push(intersect2(prev, p2, edge, bbox2));
+            if (inside) result.push(p2);
+            prev = p2;
             prevInside = inside;
           }
           points = result;
-          if (!points.length)
-            break;
+          if (!points.length) break;
         }
         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(a2, b2, edge, bbox2) {
+        return edge & 8 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[3] - a2[1]) / (b2[1] - a2[1]), bbox2[3]] : (
+          // top
+          edge & 4 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[1] - a2[1]) / (b2[1] - a2[1]), bbox2[1]] : (
+            // bottom
+            edge & 2 ? [bbox2[2], a2[1] + (b2[1] - a2[1]) * (bbox2[2] - a2[0]) / (b2[0] - a2[0])] : (
+              // right
+              edge & 1 ? [bbox2[0], a2[1] + (b2[1] - a2[1]) * (bbox2[0] - a2[0]) / (b2[0] - a2[0])] : (
+                // left
+                null
+              )
+            )
+          )
+        );
       }
-      function bitCode2(p, bbox) {
+      function bitCode2(p2, bbox2) {
         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;
+        if (p2[0] < bbox2[0]) code |= 1;
+        else if (p2[0] > bbox2[2]) code |= 2;
+        if (p2[1] < bbox2[1]) code |= 4;
+        else if (p2[1] > bbox2[3]) code |= 8;
         return code;
       }
     }
       module2.exports = whichPolygon5;
       function whichPolygon5(data) {
         var bboxes = [];
-        for (var i2 = 0; i2 < data.features.length; i2++) {
-          var feature3 = data.features[i2];
+        for (var i3 = 0; i3 < data.features.length; i3++) {
+          var feature3 = data.features[i3];
+          if (!feature3.geometry) continue;
           var coords = feature3.geometry.coordinates;
           if (feature3.geometry.type === "Polygon") {
             bboxes.push(treeItem(coords, feature3.properties));
           }
         }
         var tree = rbush().load(bboxes);
-        function query(p, multi) {
+        function query(p2, multi) {
           var output = [], result = tree.search({
-            minX: p[0],
-            minY: p[1],
-            maxX: p[0],
-            maxY: p[1]
+            minX: p2[0],
+            minY: p2[1],
+            maxX: p2[0],
+            maxY: p2[1]
           });
-          for (var i3 = 0; i3 < result.length; i3++) {
-            if (insidePolygon(result[i3].coords, p)) {
+          for (var i4 = 0; i4 < result.length; i4++) {
+            if (insidePolygon(result[i4].coords, p2)) {
               if (multi)
-                output.push(result[i3].props);
+                output.push(result[i4].props);
               else
-                return result[i3].props;
+                return result[i4].props;
             }
           }
           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)) {
-              output.push(result[i3].props);
+          for (var i4 = 0; i4 < result.length; i4++) {
+            if (polygonIntersectsBBox(result[i4].coords, bbox2)) {
+              output.push(result[i4].props);
             }
           }
           return output;
         };
         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)
-            return true;
+        if (insidePolygon(polygon2, bboxCenter)) return true;
+        for (var i3 = 0; i3 < polygon2.length; i3++) {
+          if (lineclip2(polygon2[i3], bbox2).length > 0) return true;
         }
         return false;
       }
-      function insidePolygon(rings, p) {
+      function insidePolygon(rings, p2) {
         var inside = false;
-        for (var i2 = 0, len = rings.length; i2 < len; i2++) {
-          var ring = rings[i2];
-          for (var j2 = 0, len2 = ring.length, k = len2 - 1; j2 < len2; k = j2++) {
-            if (rayIntersect(p, ring[j2], ring[k]))
-              inside = !inside;
+        for (var i3 = 0, len = rings.length; i3 < len; i3++) {
+          var ring = rings[i3];
+          for (var j2 = 0, len2 = ring.length, k2 = len2 - 1; j2 < len2; k2 = j2++) {
+            if (rayIntersect(p2, ring[j2], ring[k2])) inside = !inside;
           }
         }
         return inside;
       }
-      function rayIntersect(p, p1, p2) {
-        return p1[1] > p[1] !== p2[1] > p[1] && p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0];
+      function rayIntersect(p2, p1, p22) {
+        return p1[1] > p2[1] !== p22[1] > p2[1] && p2[0] < (p22[0] - p1[0]) * (p2[1] - p1[1]) / (p22[1] - p1[1]) + p1[0];
       }
       function treeItem(coords, props) {
         var item = {
           coords,
           props
         };
-        for (var i2 = 0; i2 < coords[0].length; i2++) {
-          var p = coords[0][i2];
-          item.minX = Math.min(item.minX, p[0]);
-          item.minY = Math.min(item.minY, p[1]);
-          item.maxX = Math.max(item.maxX, p[0]);
-          item.maxY = Math.max(item.maxY, p[1]);
+        for (var i3 = 0; i3 < coords[0].length; i3++) {
+          var p2 = coords[0][i3];
+          item.minX = Math.min(item.minX, p2[0]);
+          item.minY = Math.min(item.minY, p2[1]);
+          item.maxX = Math.max(item.maxX, p2[0]);
+          item.maxY = Math.max(item.maxY, p2[1]);
         }
         return item;
       }
       var wgs84 = require_wgs84();
       module2.exports.geometry = geometry;
       module2.exports.ring = ringArea;
-      function geometry(_) {
-        var area = 0, i2;
-        switch (_.type) {
+      function geometry(_2) {
+        var area = 0, i3;
+        switch (_2.type) {
           case "Polygon":
-            return polygonArea(_.coordinates);
+            return polygonArea(_2.coordinates);
           case "MultiPolygon":
-            for (i2 = 0; i2 < _.coordinates.length; i2++) {
-              area += polygonArea(_.coordinates[i2]);
+            for (i3 = 0; i3 < _2.coordinates.length; i3++) {
+              area += polygonArea(_2.coordinates[i3]);
             }
             return area;
           case "Point":
           case "MultiLineString":
             return 0;
           case "GeometryCollection":
-            for (i2 = 0; i2 < _.geometries.length; i2++) {
-              area += geometry(_.geometries[i2]);
+            for (i3 = 0; i3 < _2.geometries.length; i3++) {
+              area += geometry(_2.geometries[i3]);
             }
             return area;
         }
         var area = 0;
         if (coords && coords.length > 0) {
           area += Math.abs(ringArea(coords[0]));
-          for (var i2 = 1; i2 < coords.length; i2++) {
-            area -= Math.abs(ringArea(coords[i2]));
+          for (var i3 = 1; i3 < coords.length; i3++) {
+            area -= Math.abs(ringArea(coords[i3]));
           }
         }
         return area;
       }
       function ringArea(coords) {
-        var p1, p2, p3, lowerIndex, middleIndex, upperIndex, i2, area = 0, coordsLength = coords.length;
+        var p1, p2, p3, lowerIndex, middleIndex, upperIndex, i3, area = 0, coordsLength = coords.length;
         if (coordsLength > 2) {
-          for (i2 = 0; i2 < coordsLength; i2++) {
-            if (i2 === coordsLength - 2) {
+          for (i3 = 0; i3 < coordsLength; i3++) {
+            if (i3 === coordsLength - 2) {
               lowerIndex = coordsLength - 2;
               middleIndex = coordsLength - 1;
               upperIndex = 0;
-            } else if (i2 === coordsLength - 1) {
+            } else if (i3 === coordsLength - 1) {
               lowerIndex = coordsLength - 1;
               middleIndex = 0;
               upperIndex = 1;
             } else {
-              lowerIndex = i2;
-              middleIndex = i2 + 1;
-              upperIndex = i2 + 2;
+              lowerIndex = i3;
+              middleIndex = i3 + 1;
+              upperIndex = i3 + 2;
             }
             p1 = coords[lowerIndex];
             p2 = coords[middleIndex];
         }
         return area;
       }
-      function rad(_) {
-        return _ * Math.PI / 180;
+      function rad(_2) {
+        return _2 * Math.PI / 180;
       }
     }
   });
         var [lng, lat] = center;
         if (typeof lng !== "number" || typeof lat !== "number") {
           throw new Error(
-            `ERROR! Longitude and Latitude has to be numbers but where ${typeof lng} and ${typeof lat}`
+            "ERROR! Longitude and Latitude has to be numbers but where ".concat(typeof lng, " and ").concat(typeof lat)
           );
         }
         if (lng > 180 || lng < -180) {
-          throw new Error(`ERROR! Longitude has to be between -180 and 180 but was ${lng}`);
+          throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
         }
         if (lat > 90 || lat < -90) {
-          throw new Error(`ERROR! Latitude has to be between -90 and 90 but was ${lat}`);
+          throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
         }
       };
     }
     "node_modules/circle-to-polygon/input-validation/validateRadius.js"(exports2) {
       exports2.validateRadius = function validateRadius(radius) {
         if (typeof radius !== "number") {
-          throw new Error(`ERROR! Radius has to be a positive number but was: ${typeof radius}`);
+          throw new Error("ERROR! Radius has to be a positive number but was: ".concat(typeof radius));
         }
         if (radius <= 0) {
-          throw new Error(`ERROR! Radius has to be a positive number but was: ${radius}`);
+          throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
         }
       };
     }
       exports2.validateNumberOfEdges = function validateNumberOfEdges(numberOfEdges) {
         if (typeof numberOfEdges !== "number") {
           const ARGUMENT_TYPE = Array.isArray(numberOfEdges) ? "array" : typeof numberOfEdges;
-          throw new Error(`ERROR! Number of edges has to be a number but was: ${ARGUMENT_TYPE}`);
+          throw new Error("ERROR! Number of edges has to be a number but was: ".concat(ARGUMENT_TYPE));
         }
         if (numberOfEdges < 3) {
-          throw new Error(`ERROR! Number of edges has to be at least 3 but was: ${numberOfEdges}`);
+          throw new Error("ERROR! Number of edges has to be at least 3 but was: ".concat(numberOfEdges));
         }
       };
     }
       exports2.validateEarthRadius = function validateEarthRadius(earthRadius2) {
         if (typeof earthRadius2 !== "number") {
           const ARGUMENT_TYPE = Array.isArray(earthRadius2) ? "array" : typeof earthRadius2;
-          throw new Error(`ERROR! Earth radius has to be a number but was: ${ARGUMENT_TYPE}`);
+          throw new Error("ERROR! Earth radius has to be a number but was: ".concat(ARGUMENT_TYPE));
         }
         if (earthRadius2 <= 0) {
-          throw new Error(`ERROR! Earth radius has to be a positive number but was: ${earthRadius2}`);
+          throw new Error("ERROR! Earth radius has to be a positive number but was: ".concat(earthRadius2));
         }
       };
     }
       exports2.validateBearing = function validateBearing(bearing) {
         if (typeof bearing !== "number") {
           const ARGUMENT_TYPE = Array.isArray(bearing) ? "array" : typeof bearing;
-          throw new Error(`ERROR! Bearing has to be a number but was: ${ARGUMENT_TYPE}`);
+          throw new Error("ERROR! Bearing has to be a number but was: ".concat(ARGUMENT_TYPE));
         }
       };
     }
         return [toDegrees(lon), toDegrees(lat)];
       }
       module2.exports = function circleToPolygon2(center, radius, options2) {
-        var n2 = getNumberOfEdges(options2);
+        var n3 = getNumberOfEdges(options2);
         var earthRadius2 = getEarthRadius(options2);
         var bearing = getBearing(options2);
         var direction = getDirection(options2);
-        validateInput({ center, radius, numberOfEdges: n2, earthRadius: earthRadius2, bearing });
+        validateInput({ center, radius, numberOfEdges: n3, earthRadius: earthRadius2, bearing });
         var start2 = toRadians(bearing);
         var coordinates = [];
-        for (var i2 = 0; i2 < n2; ++i2) {
+        for (var i3 = 0; i3 < n3; ++i3) {
           coordinates.push(
             offset(
               center,
               radius,
               earthRadius2,
-              start2 + direction * 2 * Math.PI * -i2 / n2
+              start2 + direction * 2 * Math.PI * -i3 / n3
             )
           );
         }
     }
   });
 
-  // node_modules/polygon-clipping/dist/polygon-clipping.umd.js
-  var require_polygon_clipping_umd = __commonJS({
-    "node_modules/polygon-clipping/dist/polygon-clipping.umd.js"(exports2, module2) {
-      (function(global3, factory) {
-        typeof exports2 === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global3 = typeof globalThis !== "undefined" ? globalThis : global3 || self, global3.polygonClipping = factory());
-      })(exports2, function() {
-        "use strict";
-        function _classCallCheck(instance, Constructor) {
-          if (!(instance instanceof Constructor)) {
-            throw new TypeError("Cannot call a class as a function");
-          }
-        }
-        function _defineProperties(target, props) {
-          for (var i2 = 0; i2 < props.length; i2++) {
-            var descriptor = props[i2];
-            descriptor.enumerable = descriptor.enumerable || false;
-            descriptor.configurable = true;
-            if ("value" in descriptor)
-              descriptor.writable = true;
-            Object.defineProperty(target, descriptor.key, descriptor);
-          }
-        }
-        function _createClass(Constructor, protoProps, staticProps) {
-          if (protoProps)
-            _defineProperties(Constructor.prototype, protoProps);
-          if (staticProps)
-            _defineProperties(Constructor, staticProps);
-          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;
-        }();
-        function DEFAULT_COMPARE(a, b) {
-          return a > b ? 1 : a < b ? -1 : 0;
-        }
-        function splay(i2, t, comparator) {
-          var N = new Node(null, null);
-          var l = N;
-          var r = N;
-          while (true) {
-            var cmp2 = comparator(i2, t.key);
-            if (cmp2 < 0) {
-              if (t.left === null)
-                break;
-              if (comparator(i2, t.left.key) < 0) {
-                var y = t.left;
-                t.left = y.right;
-                y.right = t;
-                t = y;
-                if (t.left === null)
-                  break;
-              }
-              r.left = t;
-              r = t;
-              t = t.left;
-            } else if (cmp2 > 0) {
-              if (t.right === null)
-                break;
-              if (comparator(i2, t.right.key) > 0) {
-                var y = t.right;
-                t.right = y.left;
-                y.left = t;
-                t = y;
-                if (t.right === null)
-                  break;
+  // node_modules/geojson-precision/index.js
+  var require_geojson_precision = __commonJS({
+    "node_modules/geojson-precision/index.js"(exports2, module2) {
+      (function() {
+        function parse(t2, coordinatePrecision, extrasPrecision) {
+          function point(p2) {
+            return p2.map(function(e3, index) {
+              if (index < 2) {
+                return 1 * e3.toFixed(coordinatePrecision);
+              } else {
+                return 1 * e3.toFixed(extrasPrecision);
               }
-              l.right = t;
-              l = t;
-              t = t.right;
-            } else
-              break;
+            });
           }
-          l.right = t.left;
-          r.left = t.right;
-          t.left = N.right;
-          t.right = N.left;
-          return t;
-        }
-        function insert(i2, data, t, comparator) {
-          var node = new Node(i2, data);
-          if (t === null) {
-            node.left = node.right = null;
-            return node;
+          function multi(l2) {
+            return l2.map(point);
           }
-          t = splay(i2, t, comparator);
-          var cmp2 = comparator(i2, t.key);
-          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;
+          function poly(p2) {
+            return p2.map(multi);
           }
-          return node;
-        }
-        function split(key, v, comparator) {
-          var left = null;
-          var right = null;
-          if (v) {
-            v = splay(key, v, comparator);
-            var cmp2 = comparator(v.key, key);
-            if (cmp2 === 0) {
-              left = v.left;
-              right = v.right;
-            } else if (cmp2 < 0) {
-              right = v.right;
-              v.right = null;
-              left = v;
-            } else {
-              left = v.left;
-              v.left = null;
-              right = v;
+          function multiPoly(m2) {
+            return m2.map(poly);
+          }
+          function geometry(obj) {
+            if (!obj) {
+              return {};
+            }
+            switch (obj.type) {
+              case "Point":
+                obj.coordinates = point(obj.coordinates);
+                return obj;
+              case "LineString":
+              case "MultiPoint":
+                obj.coordinates = multi(obj.coordinates);
+                return obj;
+              case "Polygon":
+              case "MultiLineString":
+                obj.coordinates = poly(obj.coordinates);
+                return obj;
+              case "MultiPolygon":
+                obj.coordinates = multiPoly(obj.coordinates);
+                return obj;
+              case "GeometryCollection":
+                obj.geometries = obj.geometries.map(geometry);
+                return obj;
+              default:
+                return {};
             }
           }
-          return {
-            left,
-            right
-          };
-        }
-        function merge3(left, right, comparator) {
-          if (right === null)
-            return left;
-          if (left === null)
-            return right;
-          right = splay(left.key, right, comparator);
-          right.left = left;
-          return right;
-        }
-        function printRow(root3, prefix, isTail, out, printNode) {
-          if (root3) {
-            out("" + prefix + (isTail ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ") + printNode(root3) + "\n");
-            var indent2 = prefix + (isTail ? "    " : "\u2502   ");
-            if (root3.left)
-              printRow(root3.left, indent2, false, out, printNode);
-            if (root3.right)
-              printRow(root3.right, indent2, true, out, printNode);
+          function feature3(obj) {
+            obj.geometry = geometry(obj.geometry);
+            return obj;
           }
-        }
-        var Tree = function() {
-          function Tree2(comparator) {
-            if (comparator === void 0) {
-              comparator = DEFAULT_COMPARE;
-            }
-            this._root = null;
-            this._size = 0;
-            this._comparator = comparator;
+          function featureCollection(f2) {
+            f2.features = f2.features.map(feature3);
+            return f2;
           }
-          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;
+          function geometryCollection(g3) {
+            g3.geometries = g3.geometries.map(geometry);
+            return g3;
+          }
+          if (!t2) {
+            return t2;
+          }
+          switch (t2.type) {
+            case "Feature":
+              return feature3(t2);
+            case "GeometryCollection":
+              return geometryCollection(t2);
+            case "FeatureCollection":
+              return featureCollection(t2);
+            case "Point":
+            case "LineString":
+            case "Polygon":
+            case "MultiPoint":
+            case "MultiPolygon":
+            case "MultiLineString":
+              return geometry(t2);
+            default:
+              return t2;
+          }
+        }
+        module2.exports = parse;
+        module2.exports.parse = parse;
+      })();
+    }
+  });
+
+  // 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) {
+        return typeof obj === "object" && obj !== null;
+      }
+      function forEach(obj, cb) {
+        if (Array.isArray(obj)) {
+          obj.forEach(cb);
+        } else if (isObject2(obj)) {
+          Object.keys(obj).forEach(function(key) {
+            var val = obj[key];
+            cb(val, key);
+          });
+        }
+      }
+      function getTreeDepth(obj) {
+        var depth = 0;
+        if (Array.isArray(obj) || isObject2(obj)) {
+          forEach(obj, function(val) {
+            if (Array.isArray(val) || isObject2(val)) {
+              var tmpDepth = getTreeDepth(val);
+              if (tmpDepth > depth) {
+                depth = tmpDepth;
               }
-              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;
-            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 depth + 1;
+        }
+        return depth;
+      }
+      function stringify3(obj, options2) {
+        options2 = options2 || {};
+        var indent = JSON.stringify([1], null, get4(options2, "indent", 2)).slice(2, -3);
+        var addMargin = get4(options2, "margins", false);
+        var addArrayMargin = get4(options2, "arrayMargins", false);
+        var addObjectMargin = get4(options2, "objectMargins", false);
+        var maxLength = indent === "" ? Infinity : get4(options2, "maxLength", 80);
+        var maxNesting = get4(options2, "maxNesting", Infinity);
+        return function _stringify(obj2, currentIndent, reserved) {
+          if (obj2 && typeof obj2.toJSON === "function") {
+            obj2 = obj2.toJSON();
+          }
+          var string = JSON.stringify(obj2);
+          if (string === void 0) {
+            return string;
+          }
+          var length2 = maxLength - currentIndent.length - reserved;
+          var treeDepth = getTreeDepth(obj2);
+          if (treeDepth <= maxNesting && string.length <= length2) {
+            var prettified = prettify(string, {
+              addMargin,
+              addArrayMargin,
+              addObjectMargin
+            });
+            if (prettified.length <= length2) {
+              return prettified;
             }
-            return t;
-          };
-          Tree2.prototype.pop = function() {
-            var node = this._root;
-            if (node) {
-              while (node.left) {
-                node = node.left;
+          }
+          if (isObject2(obj2)) {
+            var nextIndent = currentIndent + indent;
+            var items = [];
+            var delimiters;
+            var comma = function(array2, index2) {
+              return index2 === array2.length - 1 ? 0 : 1;
+            };
+            if (Array.isArray(obj2)) {
+              for (var index = 0; index < obj2.length; index++) {
+                items.push(
+                  _stringify(obj2[index], nextIndent, comma(obj2, index)) || "null"
+                );
               }
-              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);
-              if (cmp2 === 0)
-                return current;
-              else if (cmp2 < 0)
-                current = current.left;
-              else
-                current = current.right;
-            }
-            return null;
-          };
-          Tree2.prototype.find = function(key) {
-            if (this._root) {
-              this._root = splay(key, this._root, this._comparator);
-              if (this._comparator(key, this._root.key) !== 0)
-                return null;
+              delimiters = "[]";
+            } else {
+              Object.keys(obj2).forEach(function(key, index2, array2) {
+                var keyPart = JSON.stringify(key) + ": ";
+                var value = _stringify(
+                  obj2[key],
+                  nextIndent,
+                  keyPart.length + comma(array2, index2)
+                );
+                if (value !== void 0) {
+                  items.push(keyPart + value);
+                }
+              });
+              delimiters = "{}";
             }
-            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;
+            if (items.length > 0) {
+              return [
+                delimiters[0],
+                indent + items.join(",\n" + nextIndent),
+                delimiters[1]
+              ].join("\n" + currentIndent);
             }
+          }
+          return string;
+        }(obj, "", 0);
+      }
+      var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
+      function prettify(string, options2) {
+        options2 = options2 || {};
+        var tokens = {
+          "{": "{",
+          "}": "}",
+          "[": "[",
+          "]": "]",
+          ",": ", ",
+          ":": ": "
+        };
+        if (options2.addMargin || options2.addObjectMargin) {
+          tokens["{"] = "{ ";
+          tokens["}"] = " }";
+        }
+        if (options2.addMargin || options2.addArrayMargin) {
+          tokens["["] = "[ ";
+          tokens["]"] = " ]";
+        }
+        return string.replace(stringOrChar, function(match, string2) {
+          return string2 ? match : tokens[match];
+        });
+      }
+      function get4(options2, name, defaultValue) {
+        return name in options2 ? options2[name] : defaultValue;
+      }
+      module2.exports = stringify3;
+    }
+  });
+
+  // node_modules/aes-js/index.js
+  var require_aes_js = __commonJS({
+    "node_modules/aes-js/index.js"(exports2, module2) {
+      (function(root3) {
+        "use strict";
+        function checkInt(value) {
+          return parseInt(value) === value;
+        }
+        function checkInts(arrayish) {
+          if (!checkInt(arrayish.length)) {
             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;
-              }
+          }
+          for (var i3 = 0; i3 < arrayish.length; i3++) {
+            if (!checkInt(arrayish[i3]) || arrayish[i3] < 0 || arrayish[i3] > 255) {
+              return false;
             }
-            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;
+          }
+          return true;
+        }
+        function coerceArray(arg, copy2) {
+          if (arg.buffer && arg.name === "Uint8Array") {
+            if (copy2) {
+              if (arg.slice) {
+                arg = arg.slice();
               } 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;
+                arg = Array.prototype.slice.call(arg);
               }
             }
-            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;
+            return arg;
+          }
+          if (Array.isArray(arg)) {
+            if (!checkInts(arg)) {
+              throw new Error("Array contains invalid value: " + arg);
             }
-            if (t)
-              while (t.left) {
-                t = t.left;
-              }
-            return t;
-          };
-          Tree2.prototype.maxNode = function(t) {
-            if (t === void 0) {
-              t = this._root;
+            return new Uint8Array(arg);
+          }
+          if (checkInt(arg.length) && checkInts(arg)) {
+            return new Uint8Array(arg);
+          }
+          throw new Error("unsupported array-like object");
+        }
+        function createArray(length2) {
+          return new Uint8Array(length2);
+        }
+        function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
+          if (sourceStart != null || sourceEnd != null) {
+            if (sourceArray.slice) {
+              sourceArray = sourceArray.slice(sourceStart, sourceEnd);
+            } else {
+              sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
             }
-            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;
+          }
+          targetArray.set(sourceArray, targetStart);
+        }
+        var convertUtf8 = /* @__PURE__ */ function() {
+          function toBytes(text) {
+            var result = [], i3 = 0;
+            text = encodeURI(text);
+            while (i3 < text.length) {
+              var c2 = text.charCodeAt(i3++);
+              if (c2 === 37) {
+                result.push(parseInt(text.substr(i3, 2), 16));
+                i3 += 2;
               } 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;
-          };
-          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;
+                result.push(c2);
               }
-              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 coerceArray(result);
+          }
+          function fromBytes(bytes) {
+            var result = [], i3 = 0;
+            while (i3 < bytes.length) {
+              var c2 = bytes[i3];
+              if (c2 < 128) {
+                result.push(String.fromCharCode(c2));
+                i3++;
+              } else if (c2 > 191 && c2 < 224) {
+                result.push(String.fromCharCode((c2 & 31) << 6 | bytes[i3 + 1] & 63));
+                i3 += 2;
+              } else {
+                result.push(String.fromCharCode((c2 & 15) << 12 | (bytes[i3 + 1] & 63) << 6 | bytes[i3 + 2] & 63));
+                i3 += 3;
               }
             }
-            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;
+            return result.join("");
+          }
+          return {
+            toBytes,
+            fromBytes
           };
-          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 convertHex = /* @__PURE__ */ function() {
+          function toBytes(text) {
+            var result = [];
+            for (var i3 = 0; i3 < text.length; i3 += 2) {
+              result.push(parseInt(text.substr(i3, 2), 16));
             }
-            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);
+            return result;
+          }
+          var Hex = "0123456789abcdef";
+          function fromBytes(bytes) {
+            var result = [];
+            for (var i3 = 0; i3 < bytes.length; i3++) {
+              var v2 = bytes[i3];
+              result.push(Hex[(v2 & 240) >> 4] + Hex[v2 & 15]);
             }
-            this._root = merge3(left, right, comparator);
-          };
-          Tree2.prototype.split = function(key) {
-            return split(key, this._root, this._comparator);
+            return result.join("");
+          }
+          return {
+            toBytes,
+            fromBytes
           };
-          return Tree2;
         }();
-        function loadRecursive(keys, values, start2, end) {
-          var size = end - start2;
-          if (size > 0) {
-            var middle = start2 + Math.floor(size / 2);
-            var key = keys[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);
-            return node;
+        var numberOfRounds = { 16: 10, 24: 12, 32: 14 };
+        var rcon = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47, 94, 188, 99, 198, 151, 53, 106, 212, 179, 125, 250, 239, 197, 145];
+        var S2 = [99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22];
+        var Si = [82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125];
+        var T1 = [3328402341, 4168907908, 4000806809, 4135287693, 4294111757, 3597364157, 3731845041, 2445657428, 1613770832, 33620227, 3462883241, 1445669757, 3892248089, 3050821474, 1303096294, 3967186586, 2412431941, 528646813, 2311702848, 4202528135, 4026202645, 2992200171, 2387036105, 4226871307, 1101901292, 3017069671, 1604494077, 1169141738, 597466303, 1403299063, 3832705686, 2613100635, 1974974402, 3791519004, 1033081774, 1277568618, 1815492186, 2118074177, 4126668546, 2211236943, 1748251740, 1369810420, 3521504564, 4193382664, 3799085459, 2883115123, 1647391059, 706024767, 134480908, 2512897874, 1176707941, 2646852446, 806885416, 932615841, 168101135, 798661301, 235341577, 605164086, 461406363, 3756188221, 3454790438, 1311188841, 2142417613, 3933566367, 302582043, 495158174, 1479289972, 874125870, 907746093, 3698224818, 3025820398, 1537253627, 2756858614, 1983593293, 3084310113, 2108928974, 1378429307, 3722699582, 1580150641, 327451799, 2790478837, 3117535592, 0, 3253595436, 1075847264, 3825007647, 2041688520, 3059440621, 3563743934, 2378943302, 1740553945, 1916352843, 2487896798, 2555137236, 2958579944, 2244988746, 3151024235, 3320835882, 1336584933, 3992714006, 2252555205, 2588757463, 1714631509, 293963156, 2319795663, 3925473552, 67240454, 4269768577, 2689618160, 2017213508, 631218106, 1269344483, 2723238387, 1571005438, 2151694528, 93294474, 1066570413, 563977660, 1882732616, 4059428100, 1673313503, 2008463041, 2950355573, 1109467491, 537923632, 3858759450, 4260623118, 3218264685, 2177748300, 403442708, 638784309, 3287084079, 3193921505, 899127202, 2286175436, 773265209, 2479146071, 1437050866, 4236148354, 2050833735, 3362022572, 3126681063, 840505643, 3866325909, 3227541664, 427917720, 2655997905, 2749160575, 1143087718, 1412049534, 999329963, 193497219, 2353415882, 3354324521, 1807268051, 672404540, 2816401017, 3160301282, 369822493, 2916866934, 3688947771, 1681011286, 1949973070, 336202270, 2454276571, 201721354, 1210328172, 3093060836, 2680341085, 3184776046, 1135389935, 3294782118, 965841320, 831886756, 3554993207, 4068047243, 3588745010, 2345191491, 1849112409, 3664604599, 26054028, 2983581028, 2622377682, 1235855840, 3630984372, 2891339514, 4092916743, 3488279077, 3395642799, 4101667470, 1202630377, 268961816, 1874508501, 4034427016, 1243948399, 1546530418, 941366308, 1470539505, 1941222599, 2546386513, 3421038627, 2715671932, 3899946140, 1042226977, 2521517021, 1639824860, 227249030, 260737669, 3765465232, 2084453954, 1907733956, 3429263018, 2420656344, 100860677, 4160157185, 470683154, 3261161891, 1781871967, 2924959737, 1773779408, 394692241, 2579611992, 974986535, 664706745, 3655459128, 3958962195, 731420851, 571543859, 3530123707, 2849626480, 126783113, 865375399, 765172662, 1008606754, 361203602, 3387549984, 2278477385, 2857719295, 1344809080, 2782912378, 59542671, 1503764984, 160008576, 437062935, 1707065306, 3622233649, 2218934982, 3496503480, 2185314755, 697932208, 1512910199, 504303377, 2075177163, 2824099068, 1841019862, 739644986];
+        var T2 = [2781242211, 2230877308, 2582542199, 2381740923, 234877682, 3184946027, 2984144751, 1418839493, 1348481072, 50462977, 2848876391, 2102799147, 434634494, 1656084439, 3863849899, 2599188086, 1167051466, 2636087938, 1082771913, 2281340285, 368048890, 3954334041, 3381544775, 201060592, 3963727277, 1739838676, 4250903202, 3930435503, 3206782108, 4149453988, 2531553906, 1536934080, 3262494647, 484572669, 2923271059, 1783375398, 1517041206, 1098792767, 49674231, 1334037708, 1550332980, 4098991525, 886171109, 150598129, 2481090929, 1940642008, 1398944049, 1059722517, 201851908, 1385547719, 1699095331, 1587397571, 674240536, 2704774806, 252314885, 3039795866, 151914247, 908333586, 2602270848, 1038082786, 651029483, 1766729511, 3447698098, 2682942837, 454166793, 2652734339, 1951935532, 775166490, 758520603, 3000790638, 4004797018, 4217086112, 4137964114, 1299594043, 1639438038, 3464344499, 2068982057, 1054729187, 1901997871, 2534638724, 4121318227, 1757008337, 0, 750906861, 1614815264, 535035132, 3363418545, 3988151131, 3201591914, 1183697867, 3647454910, 1265776953, 3734260298, 3566750796, 3903871064, 1250283471, 1807470800, 717615087, 3847203498, 384695291, 3313910595, 3617213773, 1432761139, 2484176261, 3481945413, 283769337, 100925954, 2180939647, 4037038160, 1148730428, 3123027871, 3813386408, 4087501137, 4267549603, 3229630528, 2315620239, 2906624658, 3156319645, 1215313976, 82966005, 3747855548, 3245848246, 1974459098, 1665278241, 807407632, 451280895, 251524083, 1841287890, 1283575245, 337120268, 891687699, 801369324, 3787349855, 2721421207, 3431482436, 959321879, 1469301956, 4065699751, 2197585534, 1199193405, 2898814052, 3887750493, 724703513, 2514908019, 2696962144, 2551808385, 3516813135, 2141445340, 1715741218, 2119445034, 2872807568, 2198571144, 3398190662, 700968686, 3547052216, 1009259540, 2041044702, 3803995742, 487983883, 1991105499, 1004265696, 1449407026, 1316239930, 504629770, 3683797321, 168560134, 1816667172, 3837287516, 1570751170, 1857934291, 4014189740, 2797888098, 2822345105, 2754712981, 936633572, 2347923833, 852879335, 1133234376, 1500395319, 3084545389, 2348912013, 1689376213, 3533459022, 3762923945, 3034082412, 4205598294, 133428468, 634383082, 2949277029, 2398386810, 3913789102, 403703816, 3580869306, 2297460856, 1867130149, 1918643758, 607656988, 4049053350, 3346248884, 1368901318, 600565992, 2090982877, 2632479860, 557719327, 3717614411, 3697393085, 2249034635, 2232388234, 2430627952, 1115438654, 3295786421, 2865522278, 3633334344, 84280067, 33027830, 303828494, 2747425121, 1600795957, 4188952407, 3496589753, 2434238086, 1486471617, 658119965, 3106381470, 953803233, 334231800, 3005978776, 857870609, 3151128937, 1890179545, 2298973838, 2805175444, 3056442267, 574365214, 2450884487, 550103529, 1233637070, 4289353045, 2018519080, 2057691103, 2399374476, 4166623649, 2148108681, 387583245, 3664101311, 836232934, 3330556482, 3100665960, 3280093505, 2955516313, 2002398509, 287182607, 3413881008, 4238890068, 3597515707, 975967766];
+        var T3 = [1671808611, 2089089148, 2006576759, 2072901243, 4061003762, 1807603307, 1873927791, 3310653893, 810573872, 16974337, 1739181671, 729634347, 4263110654, 3613570519, 2883997099, 1989864566, 3393556426, 2191335298, 3376449993, 2106063485, 4195741690, 1508618841, 1204391495, 4027317232, 2917941677, 3563566036, 2734514082, 2951366063, 2629772188, 2767672228, 1922491506, 3227229120, 3082974647, 4246528509, 2477669779, 644500518, 911895606, 1061256767, 4144166391, 3427763148, 878471220, 2784252325, 3845444069, 4043897329, 1905517169, 3631459288, 827548209, 356461077, 67897348, 3344078279, 593839651, 3277757891, 405286936, 2527147926, 84871685, 2595565466, 118033927, 305538066, 2157648768, 3795705826, 3945188843, 661212711, 2999812018, 1973414517, 152769033, 2208177539, 745822252, 439235610, 455947803, 1857215598, 1525593178, 2700827552, 1391895634, 994932283, 3596728278, 3016654259, 695947817, 3812548067, 795958831, 2224493444, 1408607827, 3513301457, 0, 3979133421, 543178784, 4229948412, 2982705585, 1542305371, 1790891114, 3410398667, 3201918910, 961245753, 1256100938, 1289001036, 1491644504, 3477767631, 3496721360, 4012557807, 2867154858, 4212583931, 1137018435, 1305975373, 861234739, 2241073541, 1171229253, 4178635257, 33948674, 2139225727, 1357946960, 1011120188, 2679776671, 2833468328, 1374921297, 2751356323, 1086357568, 2408187279, 2460827538, 2646352285, 944271416, 4110742005, 3168756668, 3066132406, 3665145818, 560153121, 271589392, 4279952895, 4077846003, 3530407890, 3444343245, 202643468, 322250259, 3962553324, 1608629855, 2543990167, 1154254916, 389623319, 3294073796, 2817676711, 2122513534, 1028094525, 1689045092, 1575467613, 422261273, 1939203699, 1621147744, 2174228865, 1339137615, 3699352540, 577127458, 712922154, 2427141008, 2290289544, 1187679302, 3995715566, 3100863416, 339486740, 3732514782, 1591917662, 186455563, 3681988059, 3762019296, 844522546, 978220090, 169743370, 1239126601, 101321734, 611076132, 1558493276, 3260915650, 3547250131, 2901361580, 1655096418, 2443721105, 2510565781, 3828863972, 2039214713, 3878868455, 3359869896, 928607799, 1840765549, 2374762893, 3580146133, 1322425422, 2850048425, 1823791212, 1459268694, 4094161908, 3928346602, 1706019429, 2056189050, 2934523822, 135794696, 3134549946, 2022240376, 628050469, 779246638, 472135708, 2800834470, 3032970164, 3327236038, 3894660072, 3715932637, 1956440180, 522272287, 1272813131, 3185336765, 2340818315, 2323976074, 1888542832, 1044544574, 3049550261, 1722469478, 1222152264, 50660867, 4127324150, 236067854, 1638122081, 895445557, 1475980887, 3117443513, 2257655686, 3243809217, 489110045, 2662934430, 3778599393, 4162055160, 2561878936, 288563729, 1773916777, 3648039385, 2391345038, 2493985684, 2612407707, 505560094, 2274497927, 3911240169, 3460925390, 1442818645, 678973480, 3749357023, 2358182796, 2717407649, 2306869641, 219617805, 3218761151, 3862026214, 1120306242, 1756942440, 1103331905, 2578459033, 762796589, 252780047, 2966125488, 1425844308, 3151392187, 372911126];
+        var T4 = [1667474886, 2088535288, 2004326894, 2071694838, 4075949567, 1802223062, 1869591006, 3318043793, 808472672, 16843522, 1734846926, 724270422, 4278065639, 3621216949, 2880169549, 1987484396, 3402253711, 2189597983, 3385409673, 2105378810, 4210693615, 1499065266, 1195886990, 4042263547, 2913856577, 3570689971, 2728590687, 2947541573, 2627518243, 2762274643, 1920112356, 3233831835, 3082273397, 4261223649, 2475929149, 640051788, 909531756, 1061110142, 4160160501, 3435941763, 875846760, 2779116625, 3857003729, 4059105529, 1903268834, 3638064043, 825316194, 353713962, 67374088, 3351728789, 589522246, 3284360861, 404236336, 2526454071, 84217610, 2593830191, 117901582, 303183396, 2155911963, 3806477791, 3958056653, 656894286, 2998062463, 1970642922, 151591698, 2206440989, 741110872, 437923380, 454765878, 1852748508, 1515908788, 2694904667, 1381168804, 993742198, 3604373943, 3014905469, 690584402, 3823320797, 791638366, 2223281939, 1398011302, 3520161977, 0, 3991743681, 538992704, 4244381667, 2981218425, 1532751286, 1785380564, 3419096717, 3200178535, 960056178, 1246420628, 1280103576, 1482221744, 3486468741, 3503319995, 4025428677, 2863326543, 4227536621, 1128514950, 1296947098, 859002214, 2240123921, 1162203018, 4193849577, 33687044, 2139062782, 1347481760, 1010582648, 2678045221, 2829640523, 1364325282, 2745433693, 1077985408, 2408548869, 2459086143, 2644360225, 943212656, 4126475505, 3166494563, 3065430391, 3671750063, 555836226, 269496352, 4294908645, 4092792573, 3537006015, 3452783745, 202118168, 320025894, 3974901699, 1600119230, 2543297077, 1145359496, 387397934, 3301201811, 2812801621, 2122220284, 1027426170, 1684319432, 1566435258, 421079858, 1936954854, 1616945344, 2172753945, 1330631070, 3705438115, 572679748, 707427924, 2425400123, 2290647819, 1179044492, 4008585671, 3099120491, 336870440, 3739122087, 1583276732, 185277718, 3688593069, 3772791771, 842159716, 976899700, 168435220, 1229577106, 101059084, 606366792, 1549591736, 3267517855, 3553849021, 2897014595, 1650632388, 2442242105, 2509612081, 3840161747, 2038008818, 3890688725, 3368567691, 926374254, 1835907034, 2374863873, 3587531953, 1313788572, 2846482505, 1819063512, 1448540844, 4109633523, 3941213647, 1701162954, 2054852340, 2930698567, 134748176, 3132806511, 2021165296, 623210314, 774795868, 471606328, 2795958615, 3031746419, 3334885783, 3907527627, 3722280097, 1953799400, 522133822, 1263263126, 3183336545, 2341176845, 2324333839, 1886425312, 1044267644, 3048588401, 1718004428, 1212733584, 50529542, 4143317495, 235803164, 1633788866, 892690282, 1465383342, 3115962473, 2256965911, 3250673817, 488449850, 2661202215, 3789633753, 4177007595, 2560144171, 286339874, 1768537042, 3654906025, 2391705863, 2492770099, 2610673197, 505291324, 2273808917, 3924369609, 3469625735, 1431699370, 673740880, 3755965093, 2358021891, 2711746649, 2307489801, 218961690, 3217021541, 3873845719, 1111672452, 1751693520, 1094828930, 2576986153, 757954394, 252645662, 2964376443, 1414855848, 3149649517, 370555436];
+        var T5 = [1374988112, 2118214995, 437757123, 975658646, 1001089995, 530400753, 2902087851, 1273168787, 540080725, 2910219766, 2295101073, 4110568485, 1340463100, 3307916247, 641025152, 3043140495, 3736164937, 632953703, 1172967064, 1576976609, 3274667266, 2169303058, 2370213795, 1809054150, 59727847, 361929877, 3211623147, 2505202138, 3569255213, 1484005843, 1239443753, 2395588676, 1975683434, 4102977912, 2572697195, 666464733, 3202437046, 4035489047, 3374361702, 2110667444, 1675577880, 3843699074, 2538681184, 1649639237, 2976151520, 3144396420, 4269907996, 4178062228, 1883793496, 2403728665, 2497604743, 1383856311, 2876494627, 1917518562, 3810496343, 1716890410, 3001755655, 800440835, 2261089178, 3543599269, 807962610, 599762354, 33778362, 3977675356, 2328828971, 2809771154, 4077384432, 1315562145, 1708848333, 101039829, 3509871135, 3299278474, 875451293, 2733856160, 92987698, 2767645557, 193195065, 1080094634, 1584504582, 3178106961, 1042385657, 2531067453, 3711829422, 1306967366, 2438237621, 1908694277, 67556463, 1615861247, 429456164, 3602770327, 2302690252, 1742315127, 2968011453, 126454664, 3877198648, 2043211483, 2709260871, 2084704233, 4169408201, 0, 159417987, 841739592, 504459436, 1817866830, 4245618683, 260388950, 1034867998, 908933415, 168810852, 1750902305, 2606453969, 607530554, 202008497, 2472011535, 3035535058, 463180190, 2160117071, 1641816226, 1517767529, 470948374, 3801332234, 3231722213, 1008918595, 303765277, 235474187, 4069246893, 766945465, 337553864, 1475418501, 2943682380, 4003061179, 2743034109, 4144047775, 1551037884, 1147550661, 1543208500, 2336434550, 3408119516, 3069049960, 3102011747, 3610369226, 1113818384, 328671808, 2227573024, 2236228733, 3535486456, 2935566865, 3341394285, 496906059, 3702665459, 226906860, 2009195472, 733156972, 2842737049, 294930682, 1206477858, 2835123396, 2700099354, 1451044056, 573804783, 2269728455, 3644379585, 2362090238, 2564033334, 2801107407, 2776292904, 3669462566, 1068351396, 742039012, 1350078989, 1784663195, 1417561698, 4136440770, 2430122216, 775550814, 2193862645, 2673705150, 1775276924, 1876241833, 3475313331, 3366754619, 270040487, 3902563182, 3678124923, 3441850377, 1851332852, 3969562369, 2203032232, 3868552805, 2868897406, 566021896, 4011190502, 3135740889, 1248802510, 3936291284, 699432150, 832877231, 708780849, 3332740144, 899835584, 1951317047, 4236429990, 3767586992, 866637845, 4043610186, 1106041591, 2144161806, 395441711, 1984812685, 1139781709, 3433712980, 3835036895, 2664543715, 1282050075, 3240894392, 1181045119, 2640243204, 25965917, 4203181171, 4211818798, 3009879386, 2463879762, 3910161971, 1842759443, 2597806476, 933301370, 1509430414, 3943906441, 3467192302, 3076639029, 3776767469, 2051518780, 2631065433, 1441952575, 404016761, 1942435775, 1408749034, 1610459739, 3745345300, 2017778566, 3400528769, 3110650942, 941896748, 3265478751, 371049330, 3168937228, 675039627, 4279080257, 967311729, 135050206, 3635733660, 1683407248, 2076935265, 3576870512, 1215061108, 3501741890];
+        var T6 = [1347548327, 1400783205, 3273267108, 2520393566, 3409685355, 4045380933, 2880240216, 2471224067, 1428173050, 4138563181, 2441661558, 636813900, 4233094615, 3620022987, 2149987652, 2411029155, 1239331162, 1730525723, 2554718734, 3781033664, 46346101, 310463728, 2743944855, 3328955385, 3875770207, 2501218972, 3955191162, 3667219033, 768917123, 3545789473, 692707433, 1150208456, 1786102409, 2029293177, 1805211710, 3710368113, 3065962831, 401639597, 1724457132, 3028143674, 409198410, 2196052529, 1620529459, 1164071807, 3769721975, 2226875310, 486441376, 2499348523, 1483753576, 428819965, 2274680428, 3075636216, 598438867, 3799141122, 1474502543, 711349675, 129166120, 53458370, 2592523643, 2782082824, 4063242375, 2988687269, 3120694122, 1559041666, 730517276, 2460449204, 4042459122, 2706270690, 3446004468, 3573941694, 533804130, 2328143614, 2637442643, 2695033685, 839224033, 1973745387, 957055980, 2856345839, 106852767, 1371368976, 4181598602, 1033297158, 2933734917, 1179510461, 3046200461, 91341917, 1862534868, 4284502037, 605657339, 2547432937, 3431546947, 2003294622, 3182487618, 2282195339, 954669403, 3682191598, 1201765386, 3917234703, 3388507166, 0, 2198438022, 1211247597, 2887651696, 1315723890, 4227665663, 1443857720, 507358933, 657861945, 1678381017, 560487590, 3516619604, 975451694, 2970356327, 261314535, 3535072918, 2652609425, 1333838021, 2724322336, 1767536459, 370938394, 182621114, 3854606378, 1128014560, 487725847, 185469197, 2918353863, 3106780840, 3356761769, 2237133081, 1286567175, 3152976349, 4255350624, 2683765030, 3160175349, 3309594171, 878443390, 1988838185, 3704300486, 1756818940, 1673061617, 3403100636, 272786309, 1075025698, 545572369, 2105887268, 4174560061, 296679730, 1841768865, 1260232239, 4091327024, 3960309330, 3497509347, 1814803222, 2578018489, 4195456072, 575138148, 3299409036, 446754879, 3629546796, 4011996048, 3347532110, 3252238545, 4270639778, 915985419, 3483825537, 681933534, 651868046, 2755636671, 3828103837, 223377554, 2607439820, 1649704518, 3270937875, 3901806776, 1580087799, 4118987695, 3198115200, 2087309459, 2842678573, 3016697106, 1003007129, 2802849917, 1860738147, 2077965243, 164439672, 4100872472, 32283319, 2827177882, 1709610350, 2125135846, 136428751, 3874428392, 3652904859, 3460984630, 3572145929, 3593056380, 2939266226, 824852259, 818324884, 3224740454, 930369212, 2801566410, 2967507152, 355706840, 1257309336, 4148292826, 243256656, 790073846, 2373340630, 1296297904, 1422699085, 3756299780, 3818836405, 457992840, 3099667487, 2135319889, 77422314, 1560382517, 1945798516, 788204353, 1521706781, 1385356242, 870912086, 325965383, 2358957921, 2050466060, 2388260884, 2313884476, 4006521127, 901210569, 3990953189, 1014646705, 1503449823, 1062597235, 2031621326, 3212035895, 3931371469, 1533017514, 350174575, 2256028891, 2177544179, 1052338372, 741876788, 1606591296, 1914052035, 213705253, 2334669897, 1107234197, 1899603969, 3725069491, 2631447780, 2422494913, 1635502980, 1893020342, 1950903388, 1120974935];
+        var T7 = [2807058932, 1699970625, 2764249623, 1586903591, 1808481195, 1173430173, 1487645946, 59984867, 4199882800, 1844882806, 1989249228, 1277555970, 3623636965, 3419915562, 1149249077, 2744104290, 1514790577, 459744698, 244860394, 3235995134, 1963115311, 4027744588, 2544078150, 4190530515, 1608975247, 2627016082, 2062270317, 1507497298, 2200818878, 567498868, 1764313568, 3359936201, 2305455554, 2037970062, 1047239e3, 1910319033, 1337376481, 2904027272, 2892417312, 984907214, 1243112415, 830661914, 861968209, 2135253587, 2011214180, 2927934315, 2686254721, 731183368, 1750626376, 4246310725, 1820824798, 4172763771, 3542330227, 48394827, 2404901663, 2871682645, 671593195, 3254988725, 2073724613, 145085239, 2280796200, 2779915199, 1790575107, 2187128086, 472615631, 3029510009, 4075877127, 3802222185, 4107101658, 3201631749, 1646252340, 4270507174, 1402811438, 1436590835, 3778151818, 3950355702, 3963161475, 4020912224, 2667994737, 273792366, 2331590177, 104699613, 95345982, 3175501286, 2377486676, 1560637892, 3564045318, 369057872, 4213447064, 3919042237, 1137477952, 2658625497, 1119727848, 2340947849, 1530455833, 4007360968, 172466556, 266959938, 516552836, 0, 2256734592, 3980931627, 1890328081, 1917742170, 4294704398, 945164165, 3575528878, 958871085, 3647212047, 2787207260, 1423022939, 775562294, 1739656202, 3876557655, 2530391278, 2443058075, 3310321856, 547512796, 1265195639, 437656594, 3121275539, 719700128, 3762502690, 387781147, 218828297, 3350065803, 2830708150, 2848461854, 428169201, 122466165, 3720081049, 1627235199, 648017665, 4122762354, 1002783846, 2117360635, 695634755, 3336358691, 4234721005, 4049844452, 3704280881, 2232435299, 574624663, 287343814, 612205898, 1039717051, 840019705, 2708326185, 793451934, 821288114, 1391201670, 3822090177, 376187827, 3113855344, 1224348052, 1679968233, 2361698556, 1058709744, 752375421, 2431590963, 1321699145, 3519142200, 2734591178, 188127444, 2177869557, 3727205754, 2384911031, 3215212461, 2648976442, 2450346104, 3432737375, 1180849278, 331544205, 3102249176, 4150144569, 2952102595, 2159976285, 2474404304, 766078933, 313773861, 2570832044, 2108100632, 1668212892, 3145456443, 2013908262, 418672217, 3070356634, 2594734927, 1852171925, 3867060991, 3473416636, 3907448597, 2614737639, 919489135, 164948639, 2094410160, 2997825956, 590424639, 2486224549, 1723872674, 3157750862, 3399941250, 3501252752, 3625268135, 2555048196, 3673637356, 1343127501, 4130281361, 3599595085, 2957853679, 1297403050, 81781910, 3051593425, 2283490410, 532201772, 1367295589, 3926170974, 895287692, 1953757831, 1093597963, 492483431, 3528626907, 1446242576, 1192455638, 1636604631, 209336225, 344873464, 1015671571, 669961897, 3375740769, 3857572124, 2973530695, 3747192018, 1933530610, 3464042516, 935293895, 3454686199, 2858115069, 1863638845, 3683022916, 4085369519, 3292445032, 875313188, 1080017571, 3279033885, 621591778, 1233856572, 2504130317, 24197544, 3017672716, 3835484340, 3247465558, 2220981195, 3060847922, 1551124588, 1463996600];
+        var T8 = [4104605777, 1097159550, 396673818, 660510266, 2875968315, 2638606623, 4200115116, 3808662347, 821712160, 1986918061, 3430322568, 38544885, 3856137295, 718002117, 893681702, 1654886325, 2975484382, 3122358053, 3926825029, 4274053469, 796197571, 1290801793, 1184342925, 3556361835, 2405426947, 2459735317, 1836772287, 1381620373, 3196267988, 1948373848, 3764988233, 3385345166, 3263785589, 2390325492, 1480485785, 3111247143, 3780097726, 2293045232, 548169417, 3459953789, 3746175075, 439452389, 1362321559, 1400849762, 1685577905, 1806599355, 2174754046, 137073913, 1214797936, 1174215055, 3731654548, 2079897426, 1943217067, 1258480242, 529487843, 1437280870, 3945269170, 3049390895, 3313212038, 923313619, 679998e3, 3215307299, 57326082, 377642221, 3474729866, 2041877159, 133361907, 1776460110, 3673476453, 96392454, 878845905, 2801699524, 777231668, 4082475170, 2330014213, 4142626212, 2213296395, 1626319424, 1906247262, 1846563261, 562755902, 3708173718, 1040559837, 3871163981, 1418573201, 3294430577, 114585348, 1343618912, 2566595609, 3186202582, 1078185097, 3651041127, 3896688048, 2307622919, 425408743, 3371096953, 2081048481, 1108339068, 2216610296, 0, 2156299017, 736970802, 292596766, 1517440620, 251657213, 2235061775, 2933202493, 758720310, 265905162, 1554391400, 1532285339, 908999204, 174567692, 1474760595, 4002861748, 2610011675, 3234156416, 3693126241, 2001430874, 303699484, 2478443234, 2687165888, 585122620, 454499602, 151849742, 2345119218, 3064510765, 514443284, 4044981591, 1963412655, 2581445614, 2137062819, 19308535, 1928707164, 1715193156, 4219352155, 1126790795, 600235211, 3992742070, 3841024952, 836553431, 1669664834, 2535604243, 3323011204, 1243905413, 3141400786, 4180808110, 698445255, 2653899549, 2989552604, 2253581325, 3252932727, 3004591147, 1891211689, 2487810577, 3915653703, 4237083816, 4030667424, 2100090966, 865136418, 1229899655, 953270745, 3399679628, 3557504664, 4118925222, 2061379749, 3079546586, 2915017791, 983426092, 2022837584, 1607244650, 2118541908, 2366882550, 3635996816, 972512814, 3283088770, 1568718495, 3499326569, 3576539503, 621982671, 2895723464, 410887952, 2623762152, 1002142683, 645401037, 1494807662, 2595684844, 1335535747, 2507040230, 4293295786, 3167684641, 367585007, 3885750714, 1865862730, 2668221674, 2960971305, 2763173681, 1059270954, 2777952454, 2724642869, 1320957812, 2194319100, 2429595872, 2815956275, 77089521, 3973773121, 3444575871, 2448830231, 1305906550, 4021308739, 2857194700, 2516901860, 3518358430, 1787304780, 740276417, 1699839814, 1592394909, 2352307457, 2272556026, 188821243, 1729977011, 3687994002, 274084841, 3594982253, 3613494426, 2701949495, 4162096729, 322734571, 2837966542, 1640576439, 484830689, 1202797690, 3537852828, 4067639125, 349075736, 3342319475, 4157467219, 4255800159, 1030690015, 1155237496, 2951971274, 1757691577, 607398968, 2738905026, 499347990, 3794078908, 1011452712, 227885567, 2818666809, 213114376, 3034881240, 1455525988, 3414450555, 850817237, 1817998408, 3092726480];
+        var U1 = [0, 235474187, 470948374, 303765277, 941896748, 908933415, 607530554, 708780849, 1883793496, 2118214995, 1817866830, 1649639237, 1215061108, 1181045119, 1417561698, 1517767529, 3767586992, 4003061179, 4236429990, 4069246893, 3635733660, 3602770327, 3299278474, 3400528769, 2430122216, 2664543715, 2362090238, 2193862645, 2835123396, 2801107407, 3035535058, 3135740889, 3678124923, 3576870512, 3341394285, 3374361702, 3810496343, 3977675356, 4279080257, 4043610186, 2876494627, 2776292904, 3076639029, 3110650942, 2472011535, 2640243204, 2403728665, 2169303058, 1001089995, 899835584, 666464733, 699432150, 59727847, 226906860, 530400753, 294930682, 1273168787, 1172967064, 1475418501, 1509430414, 1942435775, 2110667444, 1876241833, 1641816226, 2910219766, 2743034109, 2976151520, 3211623147, 2505202138, 2606453969, 2302690252, 2269728455, 3711829422, 3543599269, 3240894392, 3475313331, 3843699074, 3943906441, 4178062228, 4144047775, 1306967366, 1139781709, 1374988112, 1610459739, 1975683434, 2076935265, 1775276924, 1742315127, 1034867998, 866637845, 566021896, 800440835, 92987698, 193195065, 429456164, 395441711, 1984812685, 2017778566, 1784663195, 1683407248, 1315562145, 1080094634, 1383856311, 1551037884, 101039829, 135050206, 437757123, 337553864, 1042385657, 807962610, 573804783, 742039012, 2531067453, 2564033334, 2328828971, 2227573024, 2935566865, 2700099354, 3001755655, 3168937228, 3868552805, 3902563182, 4203181171, 4102977912, 3736164937, 3501741890, 3265478751, 3433712980, 1106041591, 1340463100, 1576976609, 1408749034, 2043211483, 2009195472, 1708848333, 1809054150, 832877231, 1068351396, 766945465, 599762354, 159417987, 126454664, 361929877, 463180190, 2709260871, 2943682380, 3178106961, 3009879386, 2572697195, 2538681184, 2236228733, 2336434550, 3509871135, 3745345300, 3441850377, 3274667266, 3910161971, 3877198648, 4110568485, 4211818798, 2597806476, 2497604743, 2261089178, 2295101073, 2733856160, 2902087851, 3202437046, 2968011453, 3936291284, 3835036895, 4136440770, 4169408201, 3535486456, 3702665459, 3467192302, 3231722213, 2051518780, 1951317047, 1716890410, 1750902305, 1113818384, 1282050075, 1584504582, 1350078989, 168810852, 67556463, 371049330, 404016761, 841739592, 1008918595, 775550814, 540080725, 3969562369, 3801332234, 4035489047, 4269907996, 3569255213, 3669462566, 3366754619, 3332740144, 2631065433, 2463879762, 2160117071, 2395588676, 2767645557, 2868897406, 3102011747, 3069049960, 202008497, 33778362, 270040487, 504459436, 875451293, 975658646, 675039627, 641025152, 2084704233, 1917518562, 1615861247, 1851332852, 1147550661, 1248802510, 1484005843, 1451044056, 933301370, 967311729, 733156972, 632953703, 260388950, 25965917, 328671808, 496906059, 1206477858, 1239443753, 1543208500, 1441952575, 2144161806, 1908694277, 1675577880, 1842759443, 3610369226, 3644379585, 3408119516, 3307916247, 4011190502, 3776767469, 4077384432, 4245618683, 2809771154, 2842737049, 3144396420, 3043140495, 2673705150, 2438237621, 2203032232, 2370213795];
+        var U2 = [0, 185469197, 370938394, 487725847, 741876788, 657861945, 975451694, 824852259, 1483753576, 1400783205, 1315723890, 1164071807, 1950903388, 2135319889, 1649704518, 1767536459, 2967507152, 3152976349, 2801566410, 2918353863, 2631447780, 2547432937, 2328143614, 2177544179, 3901806776, 3818836405, 4270639778, 4118987695, 3299409036, 3483825537, 3535072918, 3652904859, 2077965243, 1893020342, 1841768865, 1724457132, 1474502543, 1559041666, 1107234197, 1257309336, 598438867, 681933534, 901210569, 1052338372, 261314535, 77422314, 428819965, 310463728, 3409685355, 3224740454, 3710368113, 3593056380, 3875770207, 3960309330, 4045380933, 4195456072, 2471224067, 2554718734, 2237133081, 2388260884, 3212035895, 3028143674, 2842678573, 2724322336, 4138563181, 4255350624, 3769721975, 3955191162, 3667219033, 3516619604, 3431546947, 3347532110, 2933734917, 2782082824, 3099667487, 3016697106, 2196052529, 2313884476, 2499348523, 2683765030, 1179510461, 1296297904, 1347548327, 1533017514, 1786102409, 1635502980, 2087309459, 2003294622, 507358933, 355706840, 136428751, 53458370, 839224033, 957055980, 605657339, 790073846, 2373340630, 2256028891, 2607439820, 2422494913, 2706270690, 2856345839, 3075636216, 3160175349, 3573941694, 3725069491, 3273267108, 3356761769, 4181598602, 4063242375, 4011996048, 3828103837, 1033297158, 915985419, 730517276, 545572369, 296679730, 446754879, 129166120, 213705253, 1709610350, 1860738147, 1945798516, 2029293177, 1239331162, 1120974935, 1606591296, 1422699085, 4148292826, 4233094615, 3781033664, 3931371469, 3682191598, 3497509347, 3446004468, 3328955385, 2939266226, 2755636671, 3106780840, 2988687269, 2198438022, 2282195339, 2501218972, 2652609425, 1201765386, 1286567175, 1371368976, 1521706781, 1805211710, 1620529459, 2105887268, 1988838185, 533804130, 350174575, 164439672, 46346101, 870912086, 954669403, 636813900, 788204353, 2358957921, 2274680428, 2592523643, 2441661558, 2695033685, 2880240216, 3065962831, 3182487618, 3572145929, 3756299780, 3270937875, 3388507166, 4174560061, 4091327024, 4006521127, 3854606378, 1014646705, 930369212, 711349675, 560487590, 272786309, 457992840, 106852767, 223377554, 1678381017, 1862534868, 1914052035, 2031621326, 1211247597, 1128014560, 1580087799, 1428173050, 32283319, 182621114, 401639597, 486441376, 768917123, 651868046, 1003007129, 818324884, 1503449823, 1385356242, 1333838021, 1150208456, 1973745387, 2125135846, 1673061617, 1756818940, 2970356327, 3120694122, 2802849917, 2887651696, 2637442643, 2520393566, 2334669897, 2149987652, 3917234703, 3799141122, 4284502037, 4100872472, 3309594171, 3460984630, 3545789473, 3629546796, 2050466060, 1899603969, 1814803222, 1730525723, 1443857720, 1560382517, 1075025698, 1260232239, 575138148, 692707433, 878443390, 1062597235, 243256656, 91341917, 409198410, 325965383, 3403100636, 3252238545, 3704300486, 3620022987, 3874428392, 3990953189, 4042459122, 4227665663, 2460449204, 2578018489, 2226875310, 2411029155, 3198115200, 3046200461, 2827177882, 2743944855];
+        var U3 = [0, 218828297, 437656594, 387781147, 875313188, 958871085, 775562294, 590424639, 1750626376, 1699970625, 1917742170, 2135253587, 1551124588, 1367295589, 1180849278, 1265195639, 3501252752, 3720081049, 3399941250, 3350065803, 3835484340, 3919042237, 4270507174, 4085369519, 3102249176, 3051593425, 2734591178, 2952102595, 2361698556, 2177869557, 2530391278, 2614737639, 3145456443, 3060847922, 2708326185, 2892417312, 2404901663, 2187128086, 2504130317, 2555048196, 3542330227, 3727205754, 3375740769, 3292445032, 3876557655, 3926170974, 4246310725, 4027744588, 1808481195, 1723872674, 1910319033, 2094410160, 1608975247, 1391201670, 1173430173, 1224348052, 59984867, 244860394, 428169201, 344873464, 935293895, 984907214, 766078933, 547512796, 1844882806, 1627235199, 2011214180, 2062270317, 1507497298, 1423022939, 1137477952, 1321699145, 95345982, 145085239, 532201772, 313773861, 830661914, 1015671571, 731183368, 648017665, 3175501286, 2957853679, 2807058932, 2858115069, 2305455554, 2220981195, 2474404304, 2658625497, 3575528878, 3625268135, 3473416636, 3254988725, 3778151818, 3963161475, 4213447064, 4130281361, 3599595085, 3683022916, 3432737375, 3247465558, 3802222185, 4020912224, 4172763771, 4122762354, 3201631749, 3017672716, 2764249623, 2848461854, 2331590177, 2280796200, 2431590963, 2648976442, 104699613, 188127444, 472615631, 287343814, 840019705, 1058709744, 671593195, 621591778, 1852171925, 1668212892, 1953757831, 2037970062, 1514790577, 1463996600, 1080017571, 1297403050, 3673637356, 3623636965, 3235995134, 3454686199, 4007360968, 3822090177, 4107101658, 4190530515, 2997825956, 3215212461, 2830708150, 2779915199, 2256734592, 2340947849, 2627016082, 2443058075, 172466556, 122466165, 273792366, 492483431, 1047239e3, 861968209, 612205898, 695634755, 1646252340, 1863638845, 2013908262, 1963115311, 1446242576, 1530455833, 1277555970, 1093597963, 1636604631, 1820824798, 2073724613, 1989249228, 1436590835, 1487645946, 1337376481, 1119727848, 164948639, 81781910, 331544205, 516552836, 1039717051, 821288114, 669961897, 719700128, 2973530695, 3157750862, 2871682645, 2787207260, 2232435299, 2283490410, 2667994737, 2450346104, 3647212047, 3564045318, 3279033885, 3464042516, 3980931627, 3762502690, 4150144569, 4199882800, 3070356634, 3121275539, 2904027272, 2686254721, 2200818878, 2384911031, 2570832044, 2486224549, 3747192018, 3528626907, 3310321856, 3359936201, 3950355702, 3867060991, 4049844452, 4234721005, 1739656202, 1790575107, 2108100632, 1890328081, 1402811438, 1586903591, 1233856572, 1149249077, 266959938, 48394827, 369057872, 418672217, 1002783846, 919489135, 567498868, 752375421, 209336225, 24197544, 376187827, 459744698, 945164165, 895287692, 574624663, 793451934, 1679968233, 1764313568, 2117360635, 1933530610, 1343127501, 1560637892, 1243112415, 1192455638, 3704280881, 3519142200, 3336358691, 3419915562, 3907448597, 3857572124, 4075877127, 4294704398, 3029510009, 3113855344, 2927934315, 2744104290, 2159976285, 2377486676, 2594734927, 2544078150];
+        var U4 = [0, 151849742, 303699484, 454499602, 607398968, 758720310, 908999204, 1059270954, 1214797936, 1097159550, 1517440620, 1400849762, 1817998408, 1699839814, 2118541908, 2001430874, 2429595872, 2581445614, 2194319100, 2345119218, 3034881240, 3186202582, 2801699524, 2951971274, 3635996816, 3518358430, 3399679628, 3283088770, 4237083816, 4118925222, 4002861748, 3885750714, 1002142683, 850817237, 698445255, 548169417, 529487843, 377642221, 227885567, 77089521, 1943217067, 2061379749, 1640576439, 1757691577, 1474760595, 1592394909, 1174215055, 1290801793, 2875968315, 2724642869, 3111247143, 2960971305, 2405426947, 2253581325, 2638606623, 2487810577, 3808662347, 3926825029, 4044981591, 4162096729, 3342319475, 3459953789, 3576539503, 3693126241, 1986918061, 2137062819, 1685577905, 1836772287, 1381620373, 1532285339, 1078185097, 1229899655, 1040559837, 923313619, 740276417, 621982671, 439452389, 322734571, 137073913, 19308535, 3871163981, 4021308739, 4104605777, 4255800159, 3263785589, 3414450555, 3499326569, 3651041127, 2933202493, 2815956275, 3167684641, 3049390895, 2330014213, 2213296395, 2566595609, 2448830231, 1305906550, 1155237496, 1607244650, 1455525988, 1776460110, 1626319424, 2079897426, 1928707164, 96392454, 213114376, 396673818, 514443284, 562755902, 679998e3, 865136418, 983426092, 3708173718, 3557504664, 3474729866, 3323011204, 4180808110, 4030667424, 3945269170, 3794078908, 2507040230, 2623762152, 2272556026, 2390325492, 2975484382, 3092726480, 2738905026, 2857194700, 3973773121, 3856137295, 4274053469, 4157467219, 3371096953, 3252932727, 3673476453, 3556361835, 2763173681, 2915017791, 3064510765, 3215307299, 2156299017, 2307622919, 2459735317, 2610011675, 2081048481, 1963412655, 1846563261, 1729977011, 1480485785, 1362321559, 1243905413, 1126790795, 878845905, 1030690015, 645401037, 796197571, 274084841, 425408743, 38544885, 188821243, 3613494426, 3731654548, 3313212038, 3430322568, 4082475170, 4200115116, 3780097726, 3896688048, 2668221674, 2516901860, 2366882550, 2216610296, 3141400786, 2989552604, 2837966542, 2687165888, 1202797690, 1320957812, 1437280870, 1554391400, 1669664834, 1787304780, 1906247262, 2022837584, 265905162, 114585348, 499347990, 349075736, 736970802, 585122620, 972512814, 821712160, 2595684844, 2478443234, 2293045232, 2174754046, 3196267988, 3079546586, 2895723464, 2777952454, 3537852828, 3687994002, 3234156416, 3385345166, 4142626212, 4293295786, 3841024952, 3992742070, 174567692, 57326082, 410887952, 292596766, 777231668, 660510266, 1011452712, 893681702, 1108339068, 1258480242, 1343618912, 1494807662, 1715193156, 1865862730, 1948373848, 2100090966, 2701949495, 2818666809, 3004591147, 3122358053, 2235061775, 2352307457, 2535604243, 2653899549, 3915653703, 3764988233, 4219352155, 4067639125, 3444575871, 3294430577, 3746175075, 3594982253, 836553431, 953270745, 600235211, 718002117, 367585007, 484830689, 133361907, 251657213, 2041877159, 1891211689, 1806599355, 1654886325, 1568718495, 1418573201, 1335535747, 1184342925];
+        function convertToInt32(bytes) {
+          var result = [];
+          for (var i3 = 0; i3 < bytes.length; i3 += 4) {
+            result.push(
+              bytes[i3] << 24 | bytes[i3 + 1] << 16 | bytes[i3 + 2] << 8 | bytes[i3 + 3]
+            );
           }
-          return null;
+          return result;
         }
-        function createList(keys, 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]);
+        var AES = function(key) {
+          if (!(this instanceof AES)) {
+            throw Error("AES must be instanitated with `new`");
           }
-          p.next = null;
-          return head.next;
-        }
-        function toList(root3) {
-          var current = root3;
-          var Q = [];
-          var done = false;
-          var head = new Node(null, null);
-          var p = head;
-          while (!done) {
-            if (current) {
-              Q.push(current);
-              current = current.left;
-            } else {
-              if (Q.length > 0) {
-                current = p = p.next = Q.pop();
-                current = current.right;
-              } else
-                done = true;
-            }
+          Object.defineProperty(this, "key", {
+            value: coerceArray(key, true)
+          });
+          this._prepare();
+        };
+        AES.prototype._prepare = function() {
+          var rounds = numberOfRounds[this.key.length];
+          if (rounds == null) {
+            throw new Error("invalid key size (must be 16, 24 or 32 bytes)");
           }
-          p.next = null;
-          return head.next;
-        }
-        function sortedListToBST(list, start2, end) {
-          var size = end - start2;
-          if (size > 0) {
-            var middle = start2 + Math.floor(size / 2);
-            var left = sortedListToBST(list, start2, middle);
-            var root3 = list.head;
-            root3.left = left;
-            list.head = list.head.next;
-            root3.right = sortedListToBST(list, middle + 1, end);
-            return root3;
+          this._Ke = [];
+          this._Kd = [];
+          for (var i3 = 0; i3 <= rounds; i3++) {
+            this._Ke.push([0, 0, 0, 0]);
+            this._Kd.push([0, 0, 0, 0]);
           }
-          return null;
-        }
-        function mergeLists(l1, l2, compare) {
-          var head = new Node(null, null);
-          var p = head;
-          var p1 = l1;
-          var p2 = l2;
-          while (p1 !== null && p2 !== null) {
-            if (compare(p1.key, p2.key) < 0) {
-              p.next = p1;
-              p1 = p1.next;
+          var roundKeyCount = (rounds + 1) * 4;
+          var KC = this.key.length / 4;
+          var tk = convertToInt32(this.key);
+          var index;
+          for (var i3 = 0; i3 < KC; i3++) {
+            index = i3 >> 2;
+            this._Ke[index][i3 % 4] = tk[i3];
+            this._Kd[rounds - index][i3 % 4] = tk[i3];
+          }
+          var rconpointer = 0;
+          var t2 = KC, tt2;
+          while (t2 < roundKeyCount) {
+            tt2 = tk[KC - 1];
+            tk[0] ^= S2[tt2 >> 16 & 255] << 24 ^ S2[tt2 >> 8 & 255] << 16 ^ S2[tt2 & 255] << 8 ^ S2[tt2 >> 24 & 255] ^ rcon[rconpointer] << 24;
+            rconpointer += 1;
+            if (KC != 8) {
+              for (var i3 = 1; i3 < KC; i3++) {
+                tk[i3] ^= tk[i3 - 1];
+              }
             } else {
-              p.next = p2;
-              p2 = p2.next;
+              for (var i3 = 1; i3 < KC / 2; i3++) {
+                tk[i3] ^= tk[i3 - 1];
+              }
+              tt2 = tk[KC / 2 - 1];
+              tk[KC / 2] ^= S2[tt2 & 255] ^ S2[tt2 >> 8 & 255] << 8 ^ S2[tt2 >> 16 & 255] << 16 ^ S2[tt2 >> 24 & 255] << 24;
+              for (var i3 = KC / 2 + 1; i3 < KC; i3++) {
+                tk[i3] ^= tk[i3 - 1];
+              }
+            }
+            var i3 = 0, r2, c2;
+            while (i3 < KC && t2 < roundKeyCount) {
+              r2 = t2 >> 2;
+              c2 = t2 % 4;
+              this._Ke[r2][c2] = tk[i3];
+              this._Kd[rounds - r2][c2] = tk[i3++];
+              t2++;
             }
-            p = p.next;
-          }
-          if (p1 !== null) {
-            p.next = p1;
-          } else if (p2 !== null) {
-            p.next = p2;
-          }
-          return head.next;
-        }
-        function sort(keys, values, left, right, compare) {
-          if (left >= right)
-            return;
-          var pivot = keys[left + right >> 1];
-          var i2 = left - 1;
-          var j2 = right + 1;
-          while (true) {
-            do {
-              i2++;
-            } while (compare(keys[i2], pivot) < 0);
-            do {
-              j2--;
-            } while (compare(keys[j2], pivot) > 0);
-            if (i2 >= j2)
-              break;
-            var tmp = keys[i2];
-            keys[i2] = keys[j2];
-            keys[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);
-        }
-        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 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)
-            return null;
-          var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
-          var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x;
-          var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
-          var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y;
-          return {
-            ll: {
-              x: lowerX,
-              y: lowerY
-            },
-            ur: {
-              x: upperX,
-              y: upperY
+          for (var r2 = 1; r2 < rounds; r2++) {
+            for (var c2 = 0; c2 < 4; c2++) {
+              tt2 = this._Kd[r2][c2];
+              this._Kd[r2][c2] = U1[tt2 >> 24 & 255] ^ U2[tt2 >> 16 & 255] ^ U3[tt2 >> 8 & 255] ^ U4[tt2 & 255];
             }
-          };
+          }
         };
-        var epsilon3 = Number.EPSILON;
-        if (epsilon3 === void 0)
-          epsilon3 = Math.pow(2, -52);
-        var EPSILON_SQ = epsilon3 * epsilon3;
-        var cmp = function cmp2(a, b) {
-          if (-epsilon3 < a && a < epsilon3) {
-            if (-epsilon3 < b && b < epsilon3) {
-              return 0;
+        AES.prototype.encrypt = function(plaintext) {
+          if (plaintext.length != 16) {
+            throw new Error("invalid plaintext size (must be 16 bytes)");
+          }
+          var rounds = this._Ke.length - 1;
+          var a2 = [0, 0, 0, 0];
+          var t2 = convertToInt32(plaintext);
+          for (var i3 = 0; i3 < 4; i3++) {
+            t2[i3] ^= this._Ke[0][i3];
+          }
+          for (var r2 = 1; r2 < rounds; r2++) {
+            for (var i3 = 0; i3 < 4; i3++) {
+              a2[i3] = T1[t2[i3] >> 24 & 255] ^ T2[t2[(i3 + 1) % 4] >> 16 & 255] ^ T3[t2[(i3 + 2) % 4] >> 8 & 255] ^ T4[t2[(i3 + 3) % 4] & 255] ^ this._Ke[r2][i3];
             }
+            t2 = a2.slice();
           }
-          var ab = a - b;
-          if (ab * ab < EPSILON_SQ * a * b) {
-            return 0;
+          var result = createArray(16), tt2;
+          for (var i3 = 0; i3 < 4; i3++) {
+            tt2 = this._Ke[rounds][i3];
+            result[4 * i3] = (S2[t2[i3] >> 24 & 255] ^ tt2 >> 24) & 255;
+            result[4 * i3 + 1] = (S2[t2[(i3 + 1) % 4] >> 16 & 255] ^ tt2 >> 16) & 255;
+            result[4 * i3 + 2] = (S2[t2[(i3 + 2) % 4] >> 8 & 255] ^ tt2 >> 8) & 255;
+            result[4 * i3 + 3] = (S2[t2[(i3 + 3) % 4] & 255] ^ tt2) & 255;
           }
-          return a < b ? -1 : 1;
+          return result;
         };
-        var PtRounder = /* @__PURE__ */ function() {
-          function PtRounder2() {
-            _classCallCheck(this, PtRounder2);
-            this.reset();
+        AES.prototype.decrypt = function(ciphertext) {
+          if (ciphertext.length != 16) {
+            throw new Error("invalid ciphertext size (must be 16 bytes)");
           }
-          _createClass(PtRounder2, [{
-            key: "reset",
-            value: function reset() {
-              this.xRounder = new CoordRounder();
-              this.yRounder = new CoordRounder();
-            }
-          }, {
-            key: "round",
-            value: function round(x, y) {
-              return {
-                x: this.xRounder.round(x),
-                y: this.yRounder.round(y)
-              };
-            }
-          }]);
-          return PtRounder2;
-        }();
-        var CoordRounder = /* @__PURE__ */ function() {
-          function CoordRounder2() {
-            _classCallCheck(this, CoordRounder2);
-            this.tree = new Tree();
-            this.round(0);
+          var rounds = this._Kd.length - 1;
+          var a2 = [0, 0, 0, 0];
+          var t2 = convertToInt32(ciphertext);
+          for (var i3 = 0; i3 < 4; i3++) {
+            t2[i3] ^= this._Kd[0][i3];
           }
-          _createClass(CoordRounder2, [{
-            key: "round",
-            value: function round(coord2) {
-              var node = this.tree.add(coord2);
-              var prevNode = this.tree.prev(node);
-              if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
-                this.tree.remove(coord2);
-                return prevNode.key;
-              }
-              var nextNode = this.tree.next(node);
-              if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
-                this.tree.remove(coord2);
-                return nextNode.key;
-              }
-              return coord2;
+          for (var r2 = 1; r2 < rounds; r2++) {
+            for (var i3 = 0; i3 < 4; i3++) {
+              a2[i3] = T5[t2[i3] >> 24 & 255] ^ T6[t2[(i3 + 3) % 4] >> 16 & 255] ^ T7[t2[(i3 + 2) % 4] >> 8 & 255] ^ T8[t2[(i3 + 1) % 4] & 255] ^ this._Kd[r2][i3];
             }
-          }]);
-          return CoordRounder2;
-        }();
-        var rounder = new PtRounder();
-        var crossProduct = function crossProduct2(a, b) {
-          return a.x * b.y - a.y * b.x;
-        };
-        var dotProduct = function dotProduct2(a, b) {
-          return a.x * b.x + a.y * b.y;
-        };
-        var compareVectorAngles = function compareVectorAngles2(basePt, endPt1, endPt2) {
-          var v1 = {
-            x: endPt1.x - basePt.x,
-            y: endPt1.y - basePt.y
-          };
-          var v2 = {
-            x: endPt2.x - basePt.x,
-            y: endPt2.y - basePt.y
-          };
-          var kross = crossProduct(v1, v2);
-          return cmp(kross, 0);
-        };
-        var length = function length2(v) {
-          return Math.sqrt(dotProduct(v, v));
-        };
-        var sineOfAngle = function sineOfAngle2(pShared, pBase, pAngle) {
-          var vBase = {
-            x: pBase.x - pShared.x,
-            y: pBase.y - pShared.y
-          };
-          var vAngle = {
-            x: pAngle.x - pShared.x,
-            y: pAngle.y - pShared.y
-          };
-          return crossProduct(vAngle, vBase) / length(vAngle) / length(vBase);
+            t2 = a2.slice();
+          }
+          var result = createArray(16), tt2;
+          for (var i3 = 0; i3 < 4; i3++) {
+            tt2 = this._Kd[rounds][i3];
+            result[4 * i3] = (Si[t2[i3] >> 24 & 255] ^ tt2 >> 24) & 255;
+            result[4 * i3 + 1] = (Si[t2[(i3 + 3) % 4] >> 16 & 255] ^ tt2 >> 16) & 255;
+            result[4 * i3 + 2] = (Si[t2[(i3 + 2) % 4] >> 8 & 255] ^ tt2 >> 8) & 255;
+            result[4 * i3 + 3] = (Si[t2[(i3 + 1) % 4] & 255] ^ tt2) & 255;
+          }
+          return result;
         };
-        var cosineOfAngle = function cosineOfAngle2(pShared, pBase, pAngle) {
-          var vBase = {
-            x: pBase.x - pShared.x,
-            y: pBase.y - pShared.y
-          };
-          var vAngle = {
-            x: pAngle.x - pShared.x,
-            y: pAngle.y - pShared.y
-          };
-          return dotProduct(vAngle, vBase) / length(vAngle) / length(vBase);
+        var ModeOfOperationECB = function(key) {
+          if (!(this instanceof ModeOfOperationECB)) {
+            throw Error("AES must be instanitated with `new`");
+          }
+          this.description = "Electronic Code Block";
+          this.name = "ecb";
+          this._aes = new AES(key);
         };
-        var horizontalIntersection = function horizontalIntersection2(pt, v, y) {
-          if (v.y === 0)
-            return null;
-          return {
-            x: pt.x + v.x / v.y * (y - pt.y),
-            y
-          };
+        ModeOfOperationECB.prototype.encrypt = function(plaintext) {
+          plaintext = coerceArray(plaintext);
+          if (plaintext.length % 16 !== 0) {
+            throw new Error("invalid plaintext size (must be multiple of 16 bytes)");
+          }
+          var ciphertext = createArray(plaintext.length);
+          var block2 = createArray(16);
+          for (var i3 = 0; i3 < plaintext.length; i3 += 16) {
+            copyArray(plaintext, block2, 0, i3, i3 + 16);
+            block2 = this._aes.encrypt(block2);
+            copyArray(block2, ciphertext, i3);
+          }
+          return ciphertext;
         };
-        var verticalIntersection = function verticalIntersection2(pt, v, x) {
-          if (v.x === 0)
-            return null;
-          return {
-            x,
-            y: pt.y + v.y / v.x * (x - pt.x)
-          };
+        ModeOfOperationECB.prototype.decrypt = function(ciphertext) {
+          ciphertext = coerceArray(ciphertext);
+          if (ciphertext.length % 16 !== 0) {
+            throw new Error("invalid ciphertext size (must be multiple of 16 bytes)");
+          }
+          var plaintext = createArray(ciphertext.length);
+          var block2 = createArray(16);
+          for (var i3 = 0; i3 < ciphertext.length; i3 += 16) {
+            copyArray(ciphertext, block2, 0, i3, i3 + 16);
+            block2 = this._aes.decrypt(block2);
+            copyArray(block2, plaintext, i3);
+          }
+          return plaintext;
         };
-        var intersection = function intersection2(pt1, v1, pt2, v2) {
-          if (v1.x === 0)
-            return verticalIntersection(pt2, v2, pt1.x);
-          if (v2.x === 0)
-            return verticalIntersection(pt1, v1, pt2.x);
-          if (v1.y === 0)
-            return horizontalIntersection(pt2, v2, pt1.y);
-          if (v2.y === 0)
-            return horizontalIntersection(pt1, v1, pt2.y);
-          var kross = crossProduct(v1, v2);
-          if (kross == 0)
-            return null;
-          var ve = {
-            x: pt2.x - pt1.x,
-            y: pt2.y - pt1.y
-          };
-          var d1 = crossProduct(ve, v1) / kross;
-          var d2 = crossProduct(ve, v2) / kross;
-          var x12 = pt1.x + d2 * v1.x, x2 = pt2.x + d1 * v2.x;
-          var y12 = pt1.y + d2 * v1.y, y2 = pt2.y + d1 * v2.y;
-          var x = (x12 + x2) / 2;
-          var y = (y12 + y2) / 2;
-          return {
-            x,
-            y
-          };
+        var ModeOfOperationCBC = function(key, iv) {
+          if (!(this instanceof ModeOfOperationCBC)) {
+            throw Error("AES must be instanitated with `new`");
+          }
+          this.description = "Cipher Block Chaining";
+          this.name = "cbc";
+          if (!iv) {
+            iv = createArray(16);
+          } else if (iv.length != 16) {
+            throw new Error("invalid initialation vector size (must be 16 bytes)");
+          }
+          this._lastCipherblock = coerceArray(iv, true);
+          this._aes = new AES(key);
         };
-        var SweepEvent = /* @__PURE__ */ function() {
-          _createClass(SweepEvent2, null, [{
-            key: "compare",
-            value: function compare(a, b) {
-              var ptCmp = SweepEvent2.comparePoints(a.point, b.point);
-              if (ptCmp !== 0)
-                return ptCmp;
-              if (a.point !== b.point)
-                a.link(b);
-              if (a.isLeft !== b.isLeft)
-                return a.isLeft ? 1 : -1;
-              return Segment.compare(a.segment, b.segment);
-            }
-          }, {
-            key: "comparePoints",
-            value: function comparePoints(aPt, bPt) {
-              if (aPt.x < bPt.x)
-                return -1;
-              if (aPt.x > bPt.x)
-                return 1;
-              if (aPt.y < bPt.y)
-                return -1;
-              if (aPt.y > bPt.y)
-                return 1;
-              return 0;
-            }
-          }]);
-          function SweepEvent2(point, isLeft) {
-            _classCallCheck(this, SweepEvent2);
-            if (point.events === void 0)
-              point.events = [this];
-            else
-              point.events.push(this);
-            this.point = point;
-            this.isLeft = isLeft;
+        ModeOfOperationCBC.prototype.encrypt = function(plaintext) {
+          plaintext = coerceArray(plaintext);
+          if (plaintext.length % 16 !== 0) {
+            throw new Error("invalid plaintext size (must be multiple of 16 bytes)");
           }
-          _createClass(SweepEvent2, [{
-            key: "link",
-            value: function link2(other) {
-              if (other.point === this.point) {
-                throw new Error("Tried to link already linked events");
-              }
-              var otherEvents = other.point.events;
-              for (var i2 = 0, iMax = otherEvents.length; i2 < iMax; i2++) {
-                var evt = otherEvents[i2];
-                this.point.events.push(evt);
-                evt.point = this.point;
-              }
-              this.checkForConsuming();
-            }
-          }, {
-            key: "checkForConsuming",
-            value: function checkForConsuming() {
-              var numEvents = this.point.events.length;
-              for (var i2 = 0; i2 < numEvents; i2++) {
-                var evt1 = this.point.events[i2];
-                if (evt1.segment.consumedBy !== void 0)
-                  continue;
-                for (var j2 = i2 + 1; j2 < numEvents; j2++) {
-                  var evt2 = this.point.events[j2];
-                  if (evt2.consumedBy !== void 0)
-                    continue;
-                  if (evt1.otherSE.point.events !== evt2.otherSE.point.events)
-                    continue;
-                  evt1.segment.consume(evt2.segment);
-                }
-              }
-            }
-          }, {
-            key: "getAvailableLinkedEvents",
-            value: function getAvailableLinkedEvents() {
-              var events = [];
-              for (var i2 = 0, iMax = this.point.events.length; i2 < iMax; i2++) {
-                var evt = this.point.events[i2];
-                if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
-                  events.push(evt);
-                }
-              }
-              return events;
-            }
-          }, {
-            key: "getLeftmostComparator",
-            value: function getLeftmostComparator(baseEvent) {
-              var _this = this;
-              var cache = /* @__PURE__ */ new Map();
-              var fillCache = function fillCache2(linkedEvent) {
-                var nextEvent = linkedEvent.otherSE;
-                cache.set(linkedEvent, {
-                  sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
-                  cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
-                });
-              };
-              return function(a, b) {
-                if (!cache.has(a))
-                  fillCache(a);
-                if (!cache.has(b))
-                  fillCache(b);
-                var _cache$get = cache.get(a), asine = _cache$get.sine, acosine = _cache$get.cosine;
-                var _cache$get2 = cache.get(b), bsine = _cache$get2.sine, bcosine = _cache$get2.cosine;
-                if (asine >= 0 && bsine >= 0) {
-                  if (acosine < bcosine)
-                    return 1;
-                  if (acosine > bcosine)
-                    return -1;
-                  return 0;
-                }
-                if (asine < 0 && bsine < 0) {
-                  if (acosine < bcosine)
-                    return -1;
-                  if (acosine > bcosine)
-                    return 1;
-                  return 0;
-                }
-                if (bsine < asine)
-                  return -1;
-                if (bsine > asine)
-                  return 1;
-                return 0;
-              };
-            }
-          }]);
-          return SweepEvent2;
-        }();
-        var segmentId = 0;
-        var Segment = /* @__PURE__ */ function() {
-          _createClass(Segment2, null, [{
-            key: "compare",
-            value: function compare(a, b) {
-              var alx = a.leftSE.point.x;
-              var blx = b.leftSE.point.x;
-              var arx = a.rightSE.point.x;
-              var brx = b.rightSE.point.x;
-              if (brx < alx)
-                return 1;
-              if (arx < blx)
-                return -1;
-              var aly = a.leftSE.point.y;
-              var bly = b.leftSE.point.y;
-              var ary = a.rightSE.point.y;
-              var bry = b.rightSE.point.y;
-              if (alx < blx) {
-                if (bly < aly && bly < ary)
-                  return 1;
-                if (bly > aly && bly > ary)
-                  return -1;
-                var aCmpBLeft = a.comparePoint(b.leftSE.point);
-                if (aCmpBLeft < 0)
-                  return 1;
-                if (aCmpBLeft > 0)
-                  return -1;
-                var bCmpARight = b.comparePoint(a.rightSE.point);
-                if (bCmpARight !== 0)
-                  return bCmpARight;
-                return -1;
-              }
-              if (alx > blx) {
-                if (aly < bly && aly < bry)
-                  return -1;
-                if (aly > bly && aly > bry)
-                  return 1;
-                var bCmpALeft = b.comparePoint(a.leftSE.point);
-                if (bCmpALeft !== 0)
-                  return bCmpALeft;
-                var aCmpBRight = a.comparePoint(b.rightSE.point);
-                if (aCmpBRight < 0)
-                  return 1;
-                if (aCmpBRight > 0)
-                  return -1;
-                return 1;
-              }
-              if (aly < bly)
-                return -1;
-              if (aly > bly)
-                return 1;
-              if (arx < brx) {
-                var _bCmpARight = b.comparePoint(a.rightSE.point);
-                if (_bCmpARight !== 0)
-                  return _bCmpARight;
-              }
-              if (arx > brx) {
-                var _aCmpBRight = a.comparePoint(b.rightSE.point);
-                if (_aCmpBRight < 0)
-                  return 1;
-                if (_aCmpBRight > 0)
-                  return -1;
-              }
-              if (arx !== brx) {
-                var ay = ary - aly;
-                var ax = arx - alx;
-                var by = bry - bly;
-                var bx = brx - blx;
-                if (ay > ax && by < bx)
-                  return 1;
-                if (ay < ax && by > bx)
-                  return -1;
-              }
-              if (arx > brx)
-                return 1;
-              if (arx < brx)
-                return -1;
-              if (ary < bry)
-                return -1;
-              if (ary > bry)
-                return 1;
-              if (a.id < b.id)
-                return -1;
-              if (a.id > b.id)
-                return 1;
-              return 0;
+          var ciphertext = createArray(plaintext.length);
+          var block2 = createArray(16);
+          for (var i3 = 0; i3 < plaintext.length; i3 += 16) {
+            copyArray(plaintext, block2, 0, i3, i3 + 16);
+            for (var j2 = 0; j2 < 16; j2++) {
+              block2[j2] ^= this._lastCipherblock[j2];
             }
-          }]);
-          function Segment2(leftSE, rightSE, rings, windings) {
-            _classCallCheck(this, Segment2);
-            this.id = ++segmentId;
-            this.leftSE = leftSE;
-            leftSE.segment = this;
-            leftSE.otherSE = rightSE;
-            this.rightSE = rightSE;
-            rightSE.segment = this;
-            rightSE.otherSE = leftSE;
-            this.rings = rings;
-            this.windings = windings;
+            this._lastCipherblock = this._aes.encrypt(block2);
+            copyArray(this._lastCipherblock, ciphertext, i3);
           }
-          _createClass(Segment2, [{
-            key: "replaceRightSE",
-            value: function replaceRightSE(newRightSE) {
-              this.rightSE = newRightSE;
-              this.rightSE.segment = this;
-              this.rightSE.otherSE = this.leftSE;
-              this.leftSE.otherSE = this.rightSE;
-            }
-          }, {
-            key: "bbox",
-            value: function bbox() {
-              var y12 = this.leftSE.point.y;
-              var y2 = this.rightSE.point.y;
-              return {
-                ll: {
-                  x: this.leftSE.point.x,
-                  y: y12 < y2 ? y12 : y2
-                },
-                ur: {
-                  x: this.rightSE.point.x,
-                  y: y12 > y2 ? y12 : y2
-                }
-              };
-            }
-          }, {
-            key: "vector",
-            value: function vector() {
-              return {
-                x: this.rightSE.point.x - this.leftSE.point.x,
-                y: this.rightSE.point.y - this.leftSE.point.y
-              };
-            }
-          }, {
-            key: "isAnEndpoint",
-            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;
-            }
-          }, {
-            key: "comparePoint",
-            value: function comparePoint(point) {
-              if (this.isAnEndpoint(point))
-                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)
-                  return 0;
-                return point.x < lPt.x ? 1 : -1;
-              }
-              var yDist = (point.y - lPt.y) / v.y;
-              var xFromYDist = lPt.x + yDist * v.x;
-              if (point.x === xFromYDist)
-                return 0;
-              var xDist = (point.x - lPt.x) / v.x;
-              var yFromXDist = lPt.y + xDist * v.y;
-              if (point.y === yFromXDist)
-                return 0;
-              return point.y < yFromXDist ? -1 : 1;
-            }
-          }, {
-            key: "getIntersection",
-            value: function getIntersection(other) {
-              var tBbox = this.bbox();
-              var oBbox = other.bbox();
-              var bboxOverlap = getBboxOverlap(tBbox, oBbox);
-              if (bboxOverlap === null)
-                return null;
-              var tlp = this.leftSE.point;
-              var trp = this.rightSE.point;
-              var olp = other.leftSE.point;
-              var orp = other.rightSE.point;
-              var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
-              var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
-              var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
-              var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0;
-              if (touchesThisLSE && touchesOtherLSE) {
-                if (touchesThisRSE && !touchesOtherRSE)
-                  return trp;
-                if (!touchesThisRSE && touchesOtherRSE)
-                  return orp;
-                return null;
-              }
-              if (touchesThisLSE) {
-                if (touchesOtherRSE) {
-                  if (tlp.x === orp.x && tlp.y === orp.y)
-                    return null;
-                }
-                return tlp;
-              }
-              if (touchesOtherLSE) {
-                if (touchesThisRSE) {
-                  if (trp.x === olp.x && trp.y === olp.y)
-                    return null;
-                }
-                return olp;
-              }
-              if (touchesThisRSE && touchesOtherRSE)
-                return null;
-              if (touchesThisRSE)
-                return trp;
-              if (touchesOtherRSE)
-                return orp;
-              var pt = intersection(tlp, this.vector(), olp, other.vector());
-              if (pt === null)
-                return null;
-              if (!isInBbox(bboxOverlap, pt))
-                return null;
-              return rounder.round(pt.x, pt.y);
-            }
-          }, {
-            key: "split",
-            value: function split2(point) {
-              var newEvents = [];
-              var alreadyLinked = point.events !== void 0;
-              var newLeftSE = new SweepEvent(point, true);
-              var newRightSE = new SweepEvent(point, false);
-              var oldRightSE = this.rightSE;
-              this.replaceRightSE(newRightSE);
-              newEvents.push(newRightSE);
-              newEvents.push(newLeftSE);
-              var newSeg = new Segment2(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice());
-              if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
-                newSeg.swapEvents();
-              }
-              if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
-                this.swapEvents();
-              }
-              if (alreadyLinked) {
-                newLeftSE.checkForConsuming();
-                newRightSE.checkForConsuming();
-              }
-              return newEvents;
-            }
-          }, {
-            key: "swapEvents",
-            value: function swapEvents() {
-              var tmpEvt = this.rightSE;
-              this.rightSE = this.leftSE;
-              this.leftSE = tmpEvt;
-              this.leftSE.isLeft = true;
-              this.rightSE.isLeft = false;
-              for (var i2 = 0, iMax = this.windings.length; i2 < iMax; i2++) {
-                this.windings[i2] *= -1;
-              }
-            }
-          }, {
-            key: "consume",
-            value: function consume(other) {
-              var consumer = this;
-              var consumee = other;
-              while (consumer.consumedBy) {
-                consumer = consumer.consumedBy;
-              }
-              while (consumee.consumedBy) {
-                consumee = consumee.consumedBy;
-              }
-              var cmp2 = Segment2.compare(consumer, consumee);
-              if (cmp2 === 0)
-                return;
-              if (cmp2 > 0) {
-                var tmp = consumer;
-                consumer = consumee;
-                consumee = tmp;
-              }
-              if (consumer.prev === consumee) {
-                var _tmp = consumer;
-                consumer = consumee;
-                consumee = _tmp;
-              }
-              for (var i2 = 0, iMax = consumee.rings.length; i2 < iMax; i2++) {
-                var ring = consumee.rings[i2];
-                var winding = consumee.windings[i2];
-                var index2 = consumer.rings.indexOf(ring);
-                if (index2 === -1) {
-                  consumer.rings.push(ring);
-                  consumer.windings.push(winding);
-                } else
-                  consumer.windings[index2] += winding;
-              }
-              consumee.rings = null;
-              consumee.windings = null;
-              consumee.consumedBy = consumer;
-              consumee.leftSE.consumedBy = consumer.leftSE;
-              consumee.rightSE.consumedBy = consumer.rightSE;
-            }
-          }, {
-            key: "prevInResult",
-            value: function prevInResult() {
-              if (this._prevInResult !== void 0)
-                return this._prevInResult;
-              if (!this.prev)
-                this._prevInResult = null;
-              else if (this.prev.isInResult())
-                this._prevInResult = this.prev;
-              else
-                this._prevInResult = this.prev.prevInResult();
-              return this._prevInResult;
-            }
-          }, {
-            key: "beforeState",
-            value: function beforeState() {
-              if (this._beforeState !== void 0)
-                return this._beforeState;
-              if (!this.prev)
-                this._beforeState = {
-                  rings: [],
-                  windings: [],
-                  multiPolys: []
-                };
-              else {
-                var seg = this.prev.consumedBy || this.prev;
-                this._beforeState = seg.afterState();
-              }
-              return this._beforeState;
-            }
-          }, {
-            key: "afterState",
-            value: function afterState() {
-              if (this._afterState !== void 0)
-                return this._afterState;
-              var beforeState = this.beforeState();
-              this._afterState = {
-                rings: beforeState.rings.slice(0),
-                windings: beforeState.windings.slice(0),
-                multiPolys: []
-              };
-              var ringsAfter = this._afterState.rings;
-              var windingsAfter = this._afterState.windings;
-              var mpsAfter = this._afterState.multiPolys;
-              for (var i2 = 0, iMax = this.rings.length; i2 < iMax; i2++) {
-                var ring = this.rings[i2];
-                var winding = this.windings[i2];
-                var index2 = ringsAfter.indexOf(ring);
-                if (index2 === -1) {
-                  ringsAfter.push(ring);
-                  windingsAfter.push(winding);
-                } else
-                  windingsAfter[index2] += winding;
-              }
-              var polysAfter = [];
-              var polysExclude = [];
-              for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
-                if (windingsAfter[_i] === 0)
-                  continue;
-                var _ring = ringsAfter[_i];
-                var poly = _ring.poly;
-                if (polysExclude.indexOf(poly) !== -1)
-                  continue;
-                if (_ring.isExterior)
-                  polysAfter.push(poly);
-                else {
-                  if (polysExclude.indexOf(poly) === -1)
-                    polysExclude.push(poly);
-                  var _index = polysAfter.indexOf(_ring.poly);
-                  if (_index !== -1)
-                    polysAfter.splice(_index, 1);
-                }
-              }
-              for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
-                var mp = polysAfter[_i2].multiPoly;
-                if (mpsAfter.indexOf(mp) === -1)
-                  mpsAfter.push(mp);
-              }
-              return this._afterState;
-            }
-          }, {
-            key: "isInResult",
-            value: function isInResult() {
-              if (this.consumedBy)
-                return false;
-              if (this._isInResult !== void 0)
-                return this._isInResult;
-              var mpsBefore = this.beforeState().multiPolys;
-              var mpsAfter = this.afterState().multiPolys;
-              switch (operation.type) {
-                case "union": {
-                  var noBefores = mpsBefore.length === 0;
-                  var noAfters = mpsAfter.length === 0;
-                  this._isInResult = noBefores !== noAfters;
-                  break;
-                }
-                case "intersection": {
-                  var least;
-                  var most;
-                  if (mpsBefore.length < mpsAfter.length) {
-                    least = mpsBefore.length;
-                    most = mpsAfter.length;
-                  } else {
-                    least = mpsAfter.length;
-                    most = mpsBefore.length;
-                  }
-                  this._isInResult = most === operation.numMultiPolys && least < most;
-                  break;
-                }
-                case "xor": {
-                  var diff = Math.abs(mpsBefore.length - mpsAfter.length);
-                  this._isInResult = diff % 2 === 1;
-                  break;
-                }
-                case "difference": {
-                  var isJustSubject = function isJustSubject2(mps) {
-                    return mps.length === 1 && mps[0].isSubject;
-                  };
-                  this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
-                  break;
-                }
-                default:
-                  throw new Error("Unrecognized operation type found ".concat(operation.type));
-              }
-              return this._isInResult;
-            }
-          }], [{
-            key: "fromRing",
-            value: function fromRing(pt1, pt2, ring) {
-              var leftPt, rightPt, winding;
-              var cmpPts = SweepEvent.comparePoints(pt1, pt2);
-              if (cmpPts < 0) {
-                leftPt = pt1;
-                rightPt = pt2;
-                winding = 1;
-              } else if (cmpPts > 0) {
-                leftPt = pt2;
-                rightPt = pt1;
-                winding = -1;
-              } else
-                throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
-              var leftSE = new SweepEvent(leftPt, true);
-              var rightSE = new SweepEvent(rightPt, false);
-              return new Segment2(leftSE, rightSE, [ring], [winding]);
-            }
-          }]);
-          return Segment2;
-        }();
-        var RingIn = /* @__PURE__ */ function() {
-          function RingIn2(geomRing, poly, isExterior) {
-            _classCallCheck(this, RingIn2);
-            if (!Array.isArray(geomRing) || geomRing.length === 0) {
-              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
-            }
-            this.poly = poly;
-            this.isExterior = isExterior;
-            this.segments = [];
-            if (typeof geomRing[0][0] !== "number" || typeof geomRing[0][1] !== "number") {
-              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
-            }
-            var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
-            this.bbox = {
-              ll: {
-                x: firstPoint.x,
-                y: firstPoint.y
-              },
-              ur: {
-                x: firstPoint.x,
-                y: firstPoint.y
-              }
-            };
-            var prevPoint = firstPoint;
-            for (var i2 = 1, iMax = geomRing.length; i2 < iMax; i2++) {
-              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)
-                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;
-            }
-            if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
-              this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
-            }
+          return ciphertext;
+        };
+        ModeOfOperationCBC.prototype.decrypt = function(ciphertext) {
+          ciphertext = coerceArray(ciphertext);
+          if (ciphertext.length % 16 !== 0) {
+            throw new Error("invalid ciphertext size (must be multiple of 16 bytes)");
           }
-          _createClass(RingIn2, [{
-            key: "getSweepEvents",
-            value: function getSweepEvents() {
-              var sweepEvents = [];
-              for (var i2 = 0, iMax = this.segments.length; i2 < iMax; i2++) {
-                var segment = this.segments[i2];
-                sweepEvents.push(segment.leftSE);
-                sweepEvents.push(segment.rightSE);
-              }
-              return sweepEvents;
-            }
-          }]);
-          return RingIn2;
-        }();
-        var PolyIn = /* @__PURE__ */ function() {
-          function PolyIn2(geomPoly, multiPoly) {
-            _classCallCheck(this, PolyIn2);
-            if (!Array.isArray(geomPoly)) {
-              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
-            }
-            this.exteriorRing = new RingIn(geomPoly[0], this, true);
-            this.bbox = {
-              ll: {
-                x: this.exteriorRing.bbox.ll.x,
-                y: this.exteriorRing.bbox.ll.y
-              },
-              ur: {
-                x: this.exteriorRing.bbox.ur.x,
-                y: this.exteriorRing.bbox.ur.y
-              }
-            };
-            this.interiorRings = [];
-            for (var i2 = 1, iMax = geomPoly.length; i2 < iMax; i2++) {
-              var ring = new RingIn(geomPoly[i2], this, false);
-              if (ring.bbox.ll.x < this.bbox.ll.x)
-                this.bbox.ll.x = ring.bbox.ll.x;
-              if (ring.bbox.ll.y < this.bbox.ll.y)
-                this.bbox.ll.y = ring.bbox.ll.y;
-              if (ring.bbox.ur.x > this.bbox.ur.x)
-                this.bbox.ur.x = ring.bbox.ur.x;
-              if (ring.bbox.ur.y > this.bbox.ur.y)
-                this.bbox.ur.y = ring.bbox.ur.y;
-              this.interiorRings.push(ring);
+          var plaintext = createArray(ciphertext.length);
+          var block2 = createArray(16);
+          for (var i3 = 0; i3 < ciphertext.length; i3 += 16) {
+            copyArray(ciphertext, block2, 0, i3, i3 + 16);
+            block2 = this._aes.decrypt(block2);
+            for (var j2 = 0; j2 < 16; j2++) {
+              plaintext[i3 + j2] = block2[j2] ^ this._lastCipherblock[j2];
             }
-            this.multiPoly = multiPoly;
+            copyArray(ciphertext, this._lastCipherblock, 0, i3, i3 + 16);
           }
-          _createClass(PolyIn2, [{
-            key: "getSweepEvents",
-            value: function getSweepEvents() {
-              var sweepEvents = this.exteriorRing.getSweepEvents();
-              for (var i2 = 0, iMax = this.interiorRings.length; i2 < iMax; i2++) {
-                var ringSweepEvents = this.interiorRings[i2].getSweepEvents();
-                for (var j2 = 0, jMax = ringSweepEvents.length; j2 < jMax; j2++) {
-                  sweepEvents.push(ringSweepEvents[j2]);
-                }
-              }
-              return sweepEvents;
-            }
-          }]);
-          return PolyIn2;
-        }();
-        var MultiPolyIn = /* @__PURE__ */ function() {
-          function MultiPolyIn2(geom, isSubject) {
-            _classCallCheck(this, MultiPolyIn2);
-            if (!Array.isArray(geom)) {
-              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
-            }
-            try {
-              if (typeof geom[0][0][0] === "number")
-                geom = [geom];
-            } catch (ex) {
-            }
-            this.polys = [];
-            this.bbox = {
-              ll: {
-                x: Number.POSITIVE_INFINITY,
-                y: Number.POSITIVE_INFINITY
-              },
-              ur: {
-                x: Number.NEGATIVE_INFINITY,
-                y: Number.NEGATIVE_INFINITY
-              }
-            };
-            for (var i2 = 0, iMax = geom.length; i2 < iMax; i2++) {
-              var poly = new PolyIn(geom[i2], this);
-              if (poly.bbox.ll.x < this.bbox.ll.x)
-                this.bbox.ll.x = poly.bbox.ll.x;
-              if (poly.bbox.ll.y < this.bbox.ll.y)
-                this.bbox.ll.y = poly.bbox.ll.y;
-              if (poly.bbox.ur.x > this.bbox.ur.x)
-                this.bbox.ur.x = poly.bbox.ur.x;
-              if (poly.bbox.ur.y > this.bbox.ur.y)
-                this.bbox.ur.y = poly.bbox.ur.y;
-              this.polys.push(poly);
-            }
-            this.isSubject = isSubject;
+          return plaintext;
+        };
+        var ModeOfOperationCFB = function(key, iv, segmentSize) {
+          if (!(this instanceof ModeOfOperationCFB)) {
+            throw Error("AES must be instanitated with `new`");
           }
-          _createClass(MultiPolyIn2, [{
-            key: "getSweepEvents",
-            value: function getSweepEvents() {
-              var sweepEvents = [];
-              for (var i2 = 0, iMax = this.polys.length; i2 < iMax; i2++) {
-                var polySweepEvents = this.polys[i2].getSweepEvents();
-                for (var j2 = 0, jMax = polySweepEvents.length; j2 < jMax; j2++) {
-                  sweepEvents.push(polySweepEvents[j2]);
-                }
-              }
-              return sweepEvents;
-            }
-          }]);
-          return MultiPolyIn2;
-        }();
-        var RingOut = /* @__PURE__ */ function() {
-          _createClass(RingOut2, null, [{
-            key: "factory",
-            value: function factory(allSegments) {
-              var ringsOut = [];
-              for (var i2 = 0, iMax = allSegments.length; i2 < iMax; i2++) {
-                var segment = allSegments[i2];
-                if (!segment.isInResult() || segment.ringOut)
-                  continue;
-                var prevEvent = null;
-                var event = segment.leftSE;
-                var nextEvent = segment.rightSE;
-                var events = [event];
-                var startingPoint = event.point;
-                var intersectionLEs = [];
-                while (true) {
-                  prevEvent = event;
-                  event = nextEvent;
-                  events.push(event);
-                  if (event.point === startingPoint)
-                    break;
-                  while (true) {
-                    var availableLEs = event.getAvailableLinkedEvents();
-                    if (availableLEs.length === 0) {
-                      var firstPt = events[0].point;
-                      var lastPt = events[events.length - 1].point;
-                      throw new Error("Unable to complete output ring starting at [".concat(firstPt.x, ",") + " ".concat(firstPt.y, "]. Last matching segment found ends at") + " [".concat(lastPt.x, ", ").concat(lastPt.y, "]."));
-                    }
-                    if (availableLEs.length === 1) {
-                      nextEvent = availableLEs[0].otherSE;
-                      break;
-                    }
-                    var indexLE = null;
-                    for (var j2 = 0, jMax = intersectionLEs.length; j2 < jMax; j2++) {
-                      if (intersectionLEs[j2].point === event.point) {
-                        indexLE = j2;
-                        break;
-                      }
-                    }
-                    if (indexLE !== null) {
-                      var intersectionLE = intersectionLEs.splice(indexLE)[0];
-                      var ringEvents = events.splice(intersectionLE.index);
-                      ringEvents.unshift(ringEvents[0].otherSE);
-                      ringsOut.push(new RingOut2(ringEvents.reverse()));
-                      continue;
-                    }
-                    intersectionLEs.push({
-                      index: events.length,
-                      point: event.point
-                    });
-                    var comparator = event.getLeftmostComparator(prevEvent);
-                    nextEvent = availableLEs.sort(comparator)[0].otherSE;
-                    break;
-                  }
-                }
-                ringsOut.push(new RingOut2(events));
-              }
-              return ringsOut;
-            }
-          }]);
-          function RingOut2(events) {
-            _classCallCheck(this, RingOut2);
-            this.events = events;
-            for (var i2 = 0, iMax = events.length; i2 < iMax; i2++) {
-              events[i2].segment.ringOut = this;
-            }
-            this.poly = null;
+          this.description = "Cipher Feedback";
+          this.name = "cfb";
+          if (!iv) {
+            iv = createArray(16);
+          } else if (iv.length != 16) {
+            throw new Error("invalid initialation vector size (must be 16 size)");
           }
-          _createClass(RingOut2, [{
-            key: "getGeom",
-            value: function getGeom2() {
-              var prevPt = this.events[0].point;
-              var points = [prevPt];
-              for (var i2 = 1, iMax = this.events.length - 1; i2 < iMax; i2++) {
-                var _pt = this.events[i2].point;
-                var _nextPt = this.events[i2 + 1].point;
-                if (compareVectorAngles(_pt, prevPt, _nextPt) === 0)
-                  continue;
-                points.push(_pt);
-                prevPt = _pt;
-              }
-              if (points.length === 1)
-                return null;
-              var pt = points[0];
-              var nextPt = points[1];
-              if (compareVectorAngles(pt, prevPt, nextPt) === 0)
-                points.shift();
-              points.push(points[0]);
-              var step = this.isExteriorRing() ? 1 : -1;
-              var iStart = this.isExteriorRing() ? 0 : points.length - 1;
-              var iEnd = this.isExteriorRing() ? points.length : -1;
-              var orderedPoints = [];
-              for (var _i = iStart; _i != iEnd; _i += step) {
-                orderedPoints.push([points[_i].x, points[_i].y]);
-              }
-              return orderedPoints;
-            }
-          }, {
-            key: "isExteriorRing",
-            value: function isExteriorRing() {
-              if (this._isExteriorRing === void 0) {
-                var enclosing = this.enclosingRing();
-                this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
-              }
-              return this._isExteriorRing;
-            }
-          }, {
-            key: "enclosingRing",
-            value: function enclosingRing() {
-              if (this._enclosingRing === void 0) {
-                this._enclosingRing = this._calcEnclosingRing();
-              }
-              return this._enclosingRing;
-            }
-          }, {
-            key: "_calcEnclosingRing",
-            value: function _calcEnclosingRing() {
-              var leftMostEvt = this.events[0];
-              for (var i2 = 1, iMax = this.events.length; i2 < iMax; i2++) {
-                var evt = this.events[i2];
-                if (SweepEvent.compare(leftMostEvt, evt) > 0)
-                  leftMostEvt = evt;
-              }
-              var prevSeg = leftMostEvt.segment.prevInResult();
-              var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
-              while (true) {
-                if (!prevSeg)
-                  return null;
-                if (!prevPrevSeg)
-                  return prevSeg.ringOut;
-                if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
-                  if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
-                    return prevSeg.ringOut;
-                  } else
-                    return prevSeg.ringOut.enclosingRing();
-                }
-                prevSeg = prevPrevSeg.prevInResult();
-                prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
-              }
-            }
-          }]);
-          return RingOut2;
-        }();
-        var PolyOut = /* @__PURE__ */ function() {
-          function PolyOut2(exteriorRing) {
-            _classCallCheck(this, PolyOut2);
-            this.exteriorRing = exteriorRing;
-            exteriorRing.poly = this;
-            this.interiorRings = [];
+          if (!segmentSize) {
+            segmentSize = 1;
           }
-          _createClass(PolyOut2, [{
-            key: "addInterior",
-            value: function addInterior(ring) {
-              this.interiorRings.push(ring);
-              ring.poly = this;
-            }
-          }, {
-            key: "getGeom",
-            value: function getGeom2() {
-              var geom = [this.exteriorRing.getGeom()];
-              if (geom[0] === null)
-                return null;
-              for (var i2 = 0, iMax = this.interiorRings.length; i2 < iMax; i2++) {
-                var ringGeom = this.interiorRings[i2].getGeom();
-                if (ringGeom === null)
-                  continue;
-                geom.push(ringGeom);
-              }
-              return geom;
-            }
-          }]);
-          return PolyOut2;
-        }();
-        var MultiPolyOut = /* @__PURE__ */ function() {
-          function MultiPolyOut2(rings) {
-            _classCallCheck(this, MultiPolyOut2);
-            this.rings = rings;
-            this.polys = this._composePolys(rings);
+          this.segmentSize = segmentSize;
+          this._shiftRegister = coerceArray(iv, true);
+          this._aes = new AES(key);
+        };
+        ModeOfOperationCFB.prototype.encrypt = function(plaintext) {
+          if (plaintext.length % this.segmentSize != 0) {
+            throw new Error("invalid plaintext size (must be segmentSize bytes)");
           }
-          _createClass(MultiPolyOut2, [{
-            key: "getGeom",
-            value: function getGeom2() {
-              var geom = [];
-              for (var i2 = 0, iMax = this.polys.length; i2 < iMax; i2++) {
-                var polyGeom = this.polys[i2].getGeom();
-                if (polyGeom === null)
-                  continue;
-                geom.push(polyGeom);
-              }
-              return geom;
-            }
-          }, {
-            key: "_composePolys",
-            value: function _composePolys(rings) {
-              var polys = [];
-              for (var i2 = 0, iMax = rings.length; i2 < iMax; i2++) {
-                var ring = rings[i2];
-                if (ring.poly)
-                  continue;
-                if (ring.isExteriorRing())
-                  polys.push(new PolyOut(ring));
-                else {
-                  var enclosingRing = ring.enclosingRing();
-                  if (!enclosingRing.poly)
-                    polys.push(new PolyOut(enclosingRing));
-                  enclosingRing.poly.addInterior(ring);
-                }
-              }
-              return polys;
+          var encrypted = coerceArray(plaintext, true);
+          var xorSegment;
+          for (var i3 = 0; i3 < encrypted.length; i3 += this.segmentSize) {
+            xorSegment = this._aes.encrypt(this._shiftRegister);
+            for (var j2 = 0; j2 < this.segmentSize; j2++) {
+              encrypted[i3 + j2] ^= xorSegment[j2];
             }
-          }]);
-          return MultiPolyOut2;
-        }();
-        var SweepLine = /* @__PURE__ */ function() {
-          function SweepLine2(queue) {
-            var comparator = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : Segment.compare;
-            _classCallCheck(this, SweepLine2);
-            this.queue = queue;
-            this.tree = new Tree(comparator);
-            this.segments = [];
+            copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
+            copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i3, i3 + this.segmentSize);
           }
-          _createClass(SweepLine2, [{
-            key: "process",
-            value: function process2(event) {
-              var segment = event.segment;
-              var newEvents = [];
-              if (event.consumedBy) {
-                if (event.isLeft)
-                  this.queue.remove(event.otherSE);
-                else
-                  this.tree.remove(segment);
-                return newEvents;
-              }
-              var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
-              if (!node)
-                throw new Error("Unable to find segment #".concat(segment.id, " ") + "[".concat(segment.leftSE.point.x, ", ").concat(segment.leftSE.point.y, "] -> ") + "[".concat(segment.rightSE.point.x, ", ").concat(segment.rightSE.point.y, "] ") + "in SweepLine tree. Please submit a bug report.");
-              var prevNode = node;
-              var nextNode = node;
-              var prevSeg = void 0;
-              var nextSeg = void 0;
-              while (prevSeg === void 0) {
-                prevNode = this.tree.prev(prevNode);
-                if (prevNode === null)
-                  prevSeg = null;
-                else if (prevNode.key.consumedBy === void 0)
-                  prevSeg = prevNode.key;
-              }
-              while (nextSeg === void 0) {
-                nextNode = this.tree.next(nextNode);
-                if (nextNode === null)
-                  nextSeg = null;
-                else if (nextNode.key.consumedBy === void 0)
-                  nextSeg = nextNode.key;
-              }
-              if (event.isLeft) {
-                var prevMySplitter = null;
-                if (prevSeg) {
-                  var prevInter = prevSeg.getIntersection(segment);
-                  if (prevInter !== null) {
-                    if (!segment.isAnEndpoint(prevInter))
-                      prevMySplitter = prevInter;
-                    if (!prevSeg.isAnEndpoint(prevInter)) {
-                      var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
-                      for (var i2 = 0, iMax = newEventsFromSplit.length; i2 < iMax; i2++) {
-                        newEvents.push(newEventsFromSplit[i2]);
-                      }
-                    }
-                  }
-                }
-                var nextMySplitter = null;
-                if (nextSeg) {
-                  var nextInter = nextSeg.getIntersection(segment);
-                  if (nextInter !== null) {
-                    if (!segment.isAnEndpoint(nextInter))
-                      nextMySplitter = nextInter;
-                    if (!nextSeg.isAnEndpoint(nextInter)) {
-                      var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
-                      for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
-                        newEvents.push(_newEventsFromSplit[_i]);
-                      }
-                    }
-                  }
-                }
-                if (prevMySplitter !== null || nextMySplitter !== null) {
-                  var mySplitter = null;
-                  if (prevMySplitter === null)
-                    mySplitter = nextMySplitter;
-                  else if (nextMySplitter === null)
-                    mySplitter = prevMySplitter;
-                  else {
-                    var cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
-                    mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
-                  }
-                  this.queue.remove(segment.rightSE);
-                  newEvents.push(segment.rightSE);
-                  var _newEventsFromSplit2 = segment.split(mySplitter);
-                  for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
-                    newEvents.push(_newEventsFromSplit2[_i2]);
-                  }
-                }
-                if (newEvents.length > 0) {
-                  this.tree.remove(segment);
-                  newEvents.push(event);
-                } else {
-                  this.segments.push(segment);
-                  segment.prev = prevSeg;
-                }
-              } else {
-                if (prevSeg && nextSeg) {
-                  var inter = prevSeg.getIntersection(nextSeg);
-                  if (inter !== null) {
-                    if (!prevSeg.isAnEndpoint(inter)) {
-                      var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
-                      for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
-                        newEvents.push(_newEventsFromSplit3[_i3]);
-                      }
-                    }
-                    if (!nextSeg.isAnEndpoint(inter)) {
-                      var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
-                      for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
-                        newEvents.push(_newEventsFromSplit4[_i4]);
-                      }
-                    }
-                  }
-                }
-                this.tree.remove(segment);
-              }
-              return newEvents;
-            }
-          }, {
-            key: "_splitSafely",
-            value: function _splitSafely(seg, pt) {
-              this.tree.remove(seg);
-              var rightSE = seg.rightSE;
-              this.queue.remove(rightSE);
-              var newEvents = seg.split(pt);
-              newEvents.push(rightSE);
-              if (seg.consumedBy === void 0)
-                this.tree.insert(seg);
-              return newEvents;
-            }
-          }]);
-          return SweepLine2;
-        }();
-        var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1e6;
-        var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1e6;
-        var Operation = /* @__PURE__ */ function() {
-          function Operation2() {
-            _classCallCheck(this, Operation2);
-          }
-          _createClass(Operation2, [{
-            key: "run",
-            value: function run(type3, geom, moreGeoms) {
-              operation.type = type3;
-              rounder.reset();
-              var multipolys = [new MultiPolyIn(geom, true)];
-              for (var i2 = 0, iMax = moreGeoms.length; i2 < iMax; i2++) {
-                multipolys.push(new MultiPolyIn(moreGeoms[i2], false));
-              }
-              operation.numMultiPolys = multipolys.length;
-              if (operation.type === "difference") {
-                var subject = multipolys[0];
-                var _i = 1;
-                while (_i < multipolys.length) {
-                  if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null)
-                    _i++;
-                  else
-                    multipolys.splice(_i, 1);
-                }
-              }
-              if (operation.type === "intersection") {
-                for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
-                  var mpA = multipolys[_i2];
-                  for (var j2 = _i2 + 1, jMax = multipolys.length; j2 < jMax; j2++) {
-                    if (getBboxOverlap(mpA.bbox, multipolys[j2].bbox) === null)
-                      return [];
-                  }
-                }
-              }
-              var queue = new Tree(SweepEvent.compare);
-              for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
-                var sweepEvents = multipolys[_i3].getSweepEvents();
-                for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
-                  queue.insert(sweepEvents[_j]);
-                  if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
-                    throw new Error("Infinite loop when putting segment endpoints in a priority queue (queue size too big). Please file a bug report.");
-                  }
-                }
-              }
-              var sweepLine = new SweepLine(queue);
-              var prevQueueSize = queue.size;
-              var node = queue.pop();
-              while (node) {
-                var evt = node.key;
-                if (queue.size === prevQueueSize) {
-                  var seg = evt.segment;
-                  throw new Error("Unable to pop() ".concat(evt.isLeft ? "left" : "right", " SweepEvent ") + "[".concat(evt.point.x, ", ").concat(evt.point.y, "] from segment #").concat(seg.id, " ") + "[".concat(seg.leftSE.point.x, ", ").concat(seg.leftSE.point.y, "] -> ") + "[".concat(seg.rightSE.point.x, ", ").concat(seg.rightSE.point.y, "] from queue. ") + "Please file a bug report.");
-                }
-                if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
-                  throw new Error("Infinite loop when passing sweep line over endpoints (queue size too big). Please file a bug report.");
-                }
-                if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
-                  throw new Error("Infinite loop when passing sweep line over endpoints (too many sweep line segments). Please file a bug report.");
-                }
-                var newEvents = sweepLine.process(evt);
-                for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
-                  var _evt = newEvents[_i4];
-                  if (_evt.consumedBy === void 0)
-                    queue.insert(_evt);
-                }
-                prevQueueSize = queue.size;
-                node = queue.pop();
-              }
-              rounder.reset();
-              var ringsOut = RingOut.factory(sweepLine.segments);
-              var result = new MultiPolyOut(ringsOut);
-              return result.getGeom();
+          return encrypted;
+        };
+        ModeOfOperationCFB.prototype.decrypt = function(ciphertext) {
+          if (ciphertext.length % this.segmentSize != 0) {
+            throw new Error("invalid ciphertext size (must be segmentSize bytes)");
+          }
+          var plaintext = coerceArray(ciphertext, true);
+          var xorSegment;
+          for (var i3 = 0; i3 < plaintext.length; i3 += this.segmentSize) {
+            xorSegment = this._aes.encrypt(this._shiftRegister);
+            for (var j2 = 0; j2 < this.segmentSize; j2++) {
+              plaintext[i3 + j2] ^= xorSegment[j2];
             }
-          }]);
-          return Operation2;
-        }();
-        var operation = new Operation();
-        var union = function union2(geom) {
-          for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
-            moreGeoms[_key - 1] = arguments[_key];
+            copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
+            copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i3, i3 + this.segmentSize);
           }
-          return operation.run("union", geom, moreGeoms);
+          return plaintext;
         };
-        var intersection$1 = function intersection2(geom) {
-          for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
-            moreGeoms[_key2 - 1] = arguments[_key2];
+        var ModeOfOperationOFB = function(key, iv) {
+          if (!(this instanceof ModeOfOperationOFB)) {
+            throw Error("AES must be instanitated with `new`");
           }
-          return operation.run("intersection", geom, moreGeoms);
-        };
-        var xor = function xor2(geom) {
-          for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
-            moreGeoms[_key3 - 1] = arguments[_key3];
+          this.description = "Output Feedback";
+          this.name = "ofb";
+          if (!iv) {
+            iv = createArray(16);
+          } else if (iv.length != 16) {
+            throw new Error("invalid initialation vector size (must be 16 bytes)");
           }
-          return operation.run("xor", geom, moreGeoms);
+          this._lastPrecipher = coerceArray(iv, true);
+          this._lastPrecipherIndex = 16;
+          this._aes = new AES(key);
         };
-        var difference = function difference2(subjectGeom) {
-          for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
-            clippingGeoms[_key4 - 1] = arguments[_key4];
+        ModeOfOperationOFB.prototype.encrypt = function(plaintext) {
+          var encrypted = coerceArray(plaintext, true);
+          for (var i3 = 0; i3 < encrypted.length; i3++) {
+            if (this._lastPrecipherIndex === 16) {
+              this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
+              this._lastPrecipherIndex = 0;
+            }
+            encrypted[i3] ^= this._lastPrecipher[this._lastPrecipherIndex++];
           }
-          return operation.run("difference", subjectGeom, clippingGeoms);
+          return encrypted;
         };
-        var index = {
-          union,
-          intersection: intersection$1,
-          xor,
-          difference
+        ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
+        var Counter = function(initialValue) {
+          if (!(this instanceof Counter)) {
+            throw Error("Counter must be instanitated with `new`");
+          }
+          if (initialValue !== 0 && !initialValue) {
+            initialValue = 1;
+          }
+          if (typeof initialValue === "number") {
+            this._counter = createArray(16);
+            this.setValue(initialValue);
+          } else {
+            this.setBytes(initialValue);
+          }
         };
-        return index;
-      });
-    }
-  });
-
-  // node_modules/geojson-precision/index.js
-  var require_geojson_precision = __commonJS({
-    "node_modules/geojson-precision/index.js"(exports2, module2) {
-      (function() {
-        function parse(t, coordinatePrecision, extrasPrecision) {
-          function point(p) {
-            return p.map(function(e, index) {
-              if (index < 2) {
-                return 1 * e.toFixed(coordinatePrecision);
-              } else {
-                return 1 * e.toFixed(extrasPrecision);
-              }
-            });
+        Counter.prototype.setValue = function(value) {
+          if (typeof value !== "number" || parseInt(value) != value) {
+            throw new Error("invalid counter value (must be an integer)");
           }
-          function multi(l) {
-            return l.map(point);
+          if (value > Number.MAX_SAFE_INTEGER) {
+            throw new Error("integer value out of safe range");
           }
-          function poly(p) {
-            return p.map(multi);
+          for (var index = 15; index >= 0; --index) {
+            this._counter[index] = value % 256;
+            value = parseInt(value / 256);
           }
-          function multiPoly(m) {
-            return m.map(poly);
+        };
+        Counter.prototype.setBytes = function(bytes) {
+          bytes = coerceArray(bytes, true);
+          if (bytes.length != 16) {
+            throw new Error("invalid counter bytes size (must be 16 bytes)");
           }
-          function geometry(obj) {
-            if (!obj) {
-              return {};
-            }
-            switch (obj.type) {
-              case "Point":
-                obj.coordinates = point(obj.coordinates);
-                return obj;
-              case "LineString":
-              case "MultiPoint":
-                obj.coordinates = multi(obj.coordinates);
-                return obj;
-              case "Polygon":
-              case "MultiLineString":
-                obj.coordinates = poly(obj.coordinates);
-                return obj;
-              case "MultiPolygon":
-                obj.coordinates = multiPoly(obj.coordinates);
-                return obj;
-              case "GeometryCollection":
-                obj.geometries = obj.geometries.map(geometry);
-                return obj;
-              default:
-                return {};
-            }
-          }
-          function feature3(obj) {
-            obj.geometry = geometry(obj.geometry);
-            return obj;
-          }
-          function featureCollection(f2) {
-            f2.features = f2.features.map(feature3);
-            return f2;
-          }
-          function geometryCollection(g) {
-            g.geometries = g.geometries.map(geometry);
-            return g;
-          }
-          if (!t) {
-            return t;
-          }
-          switch (t.type) {
-            case "Feature":
-              return feature3(t);
-            case "GeometryCollection":
-              return geometryCollection(t);
-            case "FeatureCollection":
-              return featureCollection(t);
-            case "Point":
-            case "LineString":
-            case "Polygon":
-            case "MultiPoint":
-            case "MultiPolygon":
-            case "MultiLineString":
-              return geometry(t);
-            default:
-              return t;
-          }
-        }
-        module2.exports = parse;
-        module2.exports.parse = parse;
-      })();
-    }
-  });
-
-  // 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) {
-        return typeof obj === "object" && obj !== null;
-      }
-      function forEach(obj, cb) {
-        if (Array.isArray(obj)) {
-          obj.forEach(cb);
-        } else if (isObject2(obj)) {
-          Object.keys(obj).forEach(function(key) {
-            var val = obj[key];
-            cb(val, key);
-          });
-        }
-      }
-      function getTreeDepth(obj) {
-        var depth = 0;
-        if (Array.isArray(obj) || isObject2(obj)) {
-          forEach(obj, function(val) {
-            if (Array.isArray(val) || isObject2(val)) {
-              var tmpDepth = getTreeDepth(val);
-              if (tmpDepth > depth) {
-                depth = tmpDepth;
-              }
-            }
-          });
-          return depth + 1;
-        }
-        return depth;
-      }
-      function stringify3(obj, options2) {
-        options2 = options2 || {};
-        var indent2 = JSON.stringify([1], null, get4(options2, "indent", 2)).slice(2, -3);
-        var addMargin = get4(options2, "margins", false);
-        var addArrayMargin = get4(options2, "arrayMargins", false);
-        var addObjectMargin = get4(options2, "objectMargins", false);
-        var maxLength = indent2 === "" ? Infinity : get4(options2, "maxLength", 80);
-        var maxNesting = get4(options2, "maxNesting", Infinity);
-        return function _stringify(obj2, currentIndent, reserved) {
-          if (obj2 && typeof obj2.toJSON === "function") {
-            obj2 = obj2.toJSON();
-          }
-          var string = JSON.stringify(obj2);
-          if (string === void 0) {
-            return string;
-          }
-          var length = maxLength - currentIndent.length - reserved;
-          var treeDepth = getTreeDepth(obj2);
-          if (treeDepth <= maxNesting && string.length <= length) {
-            var prettified = prettify(string, {
-              addMargin,
-              addArrayMargin,
-              addObjectMargin
-            });
-            if (prettified.length <= length) {
-              return prettified;
-            }
-          }
-          if (isObject2(obj2)) {
-            var nextIndent = currentIndent + indent2;
-            var items = [];
-            var delimiters;
-            var comma = function(array2, index2) {
-              return index2 === array2.length - 1 ? 0 : 1;
-            };
-            if (Array.isArray(obj2)) {
-              for (var index = 0; index < obj2.length; index++) {
-                items.push(
-                  _stringify(obj2[index], nextIndent, comma(obj2, index)) || "null"
-                );
-              }
-              delimiters = "[]";
-            } else {
-              Object.keys(obj2).forEach(function(key, index2, array2) {
-                var keyPart = JSON.stringify(key) + ": ";
-                var value = _stringify(
-                  obj2[key],
-                  nextIndent,
-                  keyPart.length + comma(array2, index2)
-                );
-                if (value !== void 0) {
-                  items.push(keyPart + value);
-                }
-              });
-              delimiters = "{}";
-            }
-            if (items.length > 0) {
-              return [
-                delimiters[0],
-                indent2 + items.join(",\n" + nextIndent),
-                delimiters[1]
-              ].join("\n" + currentIndent);
-            }
-          }
-          return string;
-        }(obj, "", 0);
-      }
-      var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
-      function prettify(string, options2) {
-        options2 = options2 || {};
-        var tokens = {
-          "{": "{",
-          "}": "}",
-          "[": "[",
-          "]": "]",
-          ",": ", ",
-          ":": ": "
-        };
-        if (options2.addMargin || options2.addObjectMargin) {
-          tokens["{"] = "{ ";
-          tokens["}"] = " }";
-        }
-        if (options2.addMargin || options2.addArrayMargin) {
-          tokens["["] = "[ ";
-          tokens["]"] = " ]";
-        }
-        return string.replace(stringOrChar, function(match, string2) {
-          return string2 ? match : tokens[match];
-        });
-      }
-      function get4(options2, name, defaultValue) {
-        return name in options2 ? options2[name] : defaultValue;
-      }
-      module2.exports = stringify3;
-    }
-  });
-
-  // node_modules/aes-js/index.js
-  var require_aes_js = __commonJS({
-    "node_modules/aes-js/index.js"(exports2, module2) {
-      (function(root3) {
-        "use strict";
-        function checkInt(value) {
-          return parseInt(value) === value;
-        }
-        function checkInts(arrayish) {
-          if (!checkInt(arrayish.length)) {
-            return false;
-          }
-          for (var i2 = 0; i2 < arrayish.length; i2++) {
-            if (!checkInt(arrayish[i2]) || arrayish[i2] < 0 || arrayish[i2] > 255) {
-              return false;
-            }
-          }
-          return true;
-        }
-        function coerceArray(arg, copy2) {
-          if (arg.buffer && arg.name === "Uint8Array") {
-            if (copy2) {
-              if (arg.slice) {
-                arg = arg.slice();
-              } else {
-                arg = Array.prototype.slice.call(arg);
-              }
-            }
-            return arg;
-          }
-          if (Array.isArray(arg)) {
-            if (!checkInts(arg)) {
-              throw new Error("Array contains invalid value: " + arg);
-            }
-            return new Uint8Array(arg);
-          }
-          if (checkInt(arg.length) && checkInts(arg)) {
-            return new Uint8Array(arg);
-          }
-          throw new Error("unsupported array-like object");
-        }
-        function createArray(length) {
-          return new Uint8Array(length);
-        }
-        function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
-          if (sourceStart != null || sourceEnd != null) {
-            if (sourceArray.slice) {
-              sourceArray = sourceArray.slice(sourceStart, sourceEnd);
-            } else {
-              sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
-            }
-          }
-          targetArray.set(sourceArray, targetStart);
-        }
-        var convertUtf8 = function() {
-          function toBytes(text2) {
-            var result = [], i2 = 0;
-            text2 = encodeURI(text2);
-            while (i2 < text2.length) {
-              var c = text2.charCodeAt(i2++);
-              if (c === 37) {
-                result.push(parseInt(text2.substr(i2, 2), 16));
-                i2 += 2;
-              } else {
-                result.push(c);
-              }
-            }
-            return coerceArray(result);
-          }
-          function fromBytes(bytes) {
-            var result = [], i2 = 0;
-            while (i2 < bytes.length) {
-              var c = bytes[i2];
-              if (c < 128) {
-                result.push(String.fromCharCode(c));
-                i2++;
-              } else if (c > 191 && c < 224) {
-                result.push(String.fromCharCode((c & 31) << 6 | bytes[i2 + 1] & 63));
-                i2 += 2;
-              } else {
-                result.push(String.fromCharCode((c & 15) << 12 | (bytes[i2 + 1] & 63) << 6 | bytes[i2 + 2] & 63));
-                i2 += 3;
-              }
-            }
-            return result.join("");
-          }
-          return {
-            toBytes,
-            fromBytes
-          };
-        }();
-        var convertHex = function() {
-          function toBytes(text2) {
-            var result = [];
-            for (var i2 = 0; i2 < text2.length; i2 += 2) {
-              result.push(parseInt(text2.substr(i2, 2), 16));
-            }
-            return result;
-          }
-          var Hex = "0123456789abcdef";
-          function fromBytes(bytes) {
-            var result = [];
-            for (var i2 = 0; i2 < bytes.length; i2++) {
-              var v = bytes[i2];
-              result.push(Hex[(v & 240) >> 4] + Hex[v & 15]);
-            }
-            return result.join("");
-          }
-          return {
-            toBytes,
-            fromBytes
-          };
-        }();
-        var numberOfRounds = { 16: 10, 24: 12, 32: 14 };
-        var rcon = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47, 94, 188, 99, 198, 151, 53, 106, 212, 179, 125, 250, 239, 197, 145];
-        var S = [99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22];
-        var Si = [82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125];
-        var T1 = [3328402341, 4168907908, 4000806809, 4135287693, 4294111757, 3597364157, 3731845041, 2445657428, 1613770832, 33620227, 3462883241, 1445669757, 3892248089, 3050821474, 1303096294, 3967186586, 2412431941, 528646813, 2311702848, 4202528135, 4026202645, 2992200171, 2387036105, 4226871307, 1101901292, 3017069671, 1604494077, 1169141738, 597466303, 1403299063, 3832705686, 2613100635, 1974974402, 3791519004, 1033081774, 1277568618, 1815492186, 2118074177, 4126668546, 2211236943, 1748251740, 1369810420, 3521504564, 4193382664, 3799085459, 2883115123, 1647391059, 706024767, 134480908, 2512897874, 1176707941, 2646852446, 806885416, 932615841, 168101135, 798661301, 235341577, 605164086, 461406363, 3756188221, 3454790438, 1311188841, 2142417613, 3933566367, 302582043, 495158174, 1479289972, 874125870, 907746093, 3698224818, 3025820398, 1537253627, 2756858614, 1983593293, 3084310113, 2108928974, 1378429307, 3722699582, 1580150641, 327451799, 2790478837, 3117535592, 0, 3253595436, 1075847264, 3825007647, 2041688520, 3059440621, 3563743934, 2378943302, 1740553945, 1916352843, 2487896798, 2555137236, 2958579944, 2244988746, 3151024235, 3320835882, 1336584933, 3992714006, 2252555205, 2588757463, 1714631509, 293963156, 2319795663, 3925473552, 67240454, 4269768577, 2689618160, 2017213508, 631218106, 1269344483, 2723238387, 1571005438, 2151694528, 93294474, 1066570413, 563977660, 1882732616, 4059428100, 1673313503, 2008463041, 2950355573, 1109467491, 537923632, 3858759450, 4260623118, 3218264685, 2177748300, 403442708, 638784309, 3287084079, 3193921505, 899127202, 2286175436, 773265209, 2479146071, 1437050866, 4236148354, 2050833735, 3362022572, 3126681063, 840505643, 3866325909, 3227541664, 427917720, 2655997905, 2749160575, 1143087718, 1412049534, 999329963, 193497219, 2353415882, 3354324521, 1807268051, 672404540, 2816401017, 3160301282, 369822493, 2916866934, 3688947771, 1681011286, 1949973070, 336202270, 2454276571, 201721354, 1210328172, 3093060836, 2680341085, 3184776046, 1135389935, 3294782118, 965841320, 831886756, 3554993207, 4068047243, 3588745010, 2345191491, 1849112409, 3664604599, 26054028, 2983581028, 2622377682, 1235855840, 3630984372, 2891339514, 4092916743, 3488279077, 3395642799, 4101667470, 1202630377, 268961816, 1874508501, 4034427016, 1243948399, 1546530418, 941366308, 1470539505, 1941222599, 2546386513, 3421038627, 2715671932, 3899946140, 1042226977, 2521517021, 1639824860, 227249030, 260737669, 3765465232, 2084453954, 1907733956, 3429263018, 2420656344, 100860677, 4160157185, 470683154, 3261161891, 1781871967, 2924959737, 1773779408, 394692241, 2579611992, 974986535, 664706745, 3655459128, 3958962195, 731420851, 571543859, 3530123707, 2849626480, 126783113, 865375399, 765172662, 1008606754, 361203602, 3387549984, 2278477385, 2857719295, 1344809080, 2782912378, 59542671, 1503764984, 160008576, 437062935, 1707065306, 3622233649, 2218934982, 3496503480, 2185314755, 697932208, 1512910199, 504303377, 2075177163, 2824099068, 1841019862, 739644986];
-        var T2 = [2781242211, 2230877308, 2582542199, 2381740923, 234877682, 3184946027, 2984144751, 1418839493, 1348481072, 50462977, 2848876391, 2102799147, 434634494, 1656084439, 3863849899, 2599188086, 1167051466, 2636087938, 1082771913, 2281340285, 368048890, 3954334041, 3381544775, 201060592, 3963727277, 1739838676, 4250903202, 3930435503, 3206782108, 4149453988, 2531553906, 1536934080, 3262494647, 484572669, 2923271059, 1783375398, 1517041206, 1098792767, 49674231, 1334037708, 1550332980, 4098991525, 886171109, 150598129, 2481090929, 1940642008, 1398944049, 1059722517, 201851908, 1385547719, 1699095331, 1587397571, 674240536, 2704774806, 252314885, 3039795866, 151914247, 908333586, 2602270848, 1038082786, 651029483, 1766729511, 3447698098, 2682942837, 454166793, 2652734339, 1951935532, 775166490, 758520603, 3000790638, 4004797018, 4217086112, 4137964114, 1299594043, 1639438038, 3464344499, 2068982057, 1054729187, 1901997871, 2534638724, 4121318227, 1757008337, 0, 750906861, 1614815264, 535035132, 3363418545, 3988151131, 3201591914, 1183697867, 3647454910, 1265776953, 3734260298, 3566750796, 3903871064, 1250283471, 1807470800, 717615087, 3847203498, 384695291, 3313910595, 3617213773, 1432761139, 2484176261, 3481945413, 283769337, 100925954, 2180939647, 4037038160, 1148730428, 3123027871, 3813386408, 4087501137, 4267549603, 3229630528, 2315620239, 2906624658, 3156319645, 1215313976, 82966005, 3747855548, 3245848246, 1974459098, 1665278241, 807407632, 451280895, 251524083, 1841287890, 1283575245, 337120268, 891687699, 801369324, 3787349855, 2721421207, 3431482436, 959321879, 1469301956, 4065699751, 2197585534, 1199193405, 2898814052, 3887750493, 724703513, 2514908019, 2696962144, 2551808385, 3516813135, 2141445340, 1715741218, 2119445034, 2872807568, 2198571144, 3398190662, 700968686, 3547052216, 1009259540, 2041044702, 3803995742, 487983883, 1991105499, 1004265696, 1449407026, 1316239930, 504629770, 3683797321, 168560134, 1816667172, 3837287516, 1570751170, 1857934291, 4014189740, 2797888098, 2822345105, 2754712981, 936633572, 2347923833, 852879335, 1133234376, 1500395319, 3084545389, 2348912013, 1689376213, 3533459022, 3762923945, 3034082412, 4205598294, 133428468, 634383082, 2949277029, 2398386810, 3913789102, 403703816, 3580869306, 2297460856, 1867130149, 1918643758, 607656988, 4049053350, 3346248884, 1368901318, 600565992, 2090982877, 2632479860, 557719327, 3717614411, 3697393085, 2249034635, 2232388234, 2430627952, 1115438654, 3295786421, 2865522278, 3633334344, 84280067, 33027830, 303828494, 2747425121, 1600795957, 4188952407, 3496589753, 2434238086, 1486471617, 658119965, 3106381470, 953803233, 334231800, 3005978776, 857870609, 3151128937, 1890179545, 2298973838, 2805175444, 3056442267, 574365214, 2450884487, 550103529, 1233637070, 4289353045, 2018519080, 2057691103, 2399374476, 4166623649, 2148108681, 387583245, 3664101311, 836232934, 3330556482, 3100665960, 3280093505, 2955516313, 2002398509, 287182607, 3413881008, 4238890068, 3597515707, 975967766];
-        var T3 = [1671808611, 2089089148, 2006576759, 2072901243, 4061003762, 1807603307, 1873927791, 3310653893, 810573872, 16974337, 1739181671, 729634347, 4263110654, 3613570519, 2883997099, 1989864566, 3393556426, 2191335298, 3376449993, 2106063485, 4195741690, 1508618841, 1204391495, 4027317232, 2917941677, 3563566036, 2734514082, 2951366063, 2629772188, 2767672228, 1922491506, 3227229120, 3082974647, 4246528509, 2477669779, 644500518, 911895606, 1061256767, 4144166391, 3427763148, 878471220, 2784252325, 3845444069, 4043897329, 1905517169, 3631459288, 827548209, 356461077, 67897348, 3344078279, 593839651, 3277757891, 405286936, 2527147926, 84871685, 2595565466, 118033927, 305538066, 2157648768, 3795705826, 3945188843, 661212711, 2999812018, 1973414517, 152769033, 2208177539, 745822252, 439235610, 455947803, 1857215598, 1525593178, 2700827552, 1391895634, 994932283, 3596728278, 3016654259, 695947817, 3812548067, 795958831, 2224493444, 1408607827, 3513301457, 0, 3979133421, 543178784, 4229948412, 2982705585, 1542305371, 1790891114, 3410398667, 3201918910, 961245753, 1256100938, 1289001036, 1491644504, 3477767631, 3496721360, 4012557807, 2867154858, 4212583931, 1137018435, 1305975373, 861234739, 2241073541, 1171229253, 4178635257, 33948674, 2139225727, 1357946960, 1011120188, 2679776671, 2833468328, 1374921297, 2751356323, 1086357568, 2408187279, 2460827538, 2646352285, 944271416, 4110742005, 3168756668, 3066132406, 3665145818, 560153121, 271589392, 4279952895, 4077846003, 3530407890, 3444343245, 202643468, 322250259, 3962553324, 1608629855, 2543990167, 1154254916, 389623319, 3294073796, 2817676711, 2122513534, 1028094525, 1689045092, 1575467613, 422261273, 1939203699, 1621147744, 2174228865, 1339137615, 3699352540, 577127458, 712922154, 2427141008, 2290289544, 1187679302, 3995715566, 3100863416, 339486740, 3732514782, 1591917662, 186455563, 3681988059, 3762019296, 844522546, 978220090, 169743370, 1239126601, 101321734, 611076132, 1558493276, 3260915650, 3547250131, 2901361580, 1655096418, 2443721105, 2510565781, 3828863972, 2039214713, 3878868455, 3359869896, 928607799, 1840765549, 2374762893, 3580146133, 1322425422, 2850048425, 1823791212, 1459268694, 4094161908, 3928346602, 1706019429, 2056189050, 2934523822, 135794696, 3134549946, 2022240376, 628050469, 779246638, 472135708, 2800834470, 3032970164, 3327236038, 3894660072, 3715932637, 1956440180, 522272287, 1272813131, 3185336765, 2340818315, 2323976074, 1888542832, 1044544574, 3049550261, 1722469478, 1222152264, 50660867, 4127324150, 236067854, 1638122081, 895445557, 1475980887, 3117443513, 2257655686, 3243809217, 489110045, 2662934430, 3778599393, 4162055160, 2561878936, 288563729, 1773916777, 3648039385, 2391345038, 2493985684, 2612407707, 505560094, 2274497927, 3911240169, 3460925390, 1442818645, 678973480, 3749357023, 2358182796, 2717407649, 2306869641, 219617805, 3218761151, 3862026214, 1120306242, 1756942440, 1103331905, 2578459033, 762796589, 252780047, 2966125488, 1425844308, 3151392187, 372911126];
-        var T4 = [1667474886, 2088535288, 2004326894, 2071694838, 4075949567, 1802223062, 1869591006, 3318043793, 808472672, 16843522, 1734846926, 724270422, 4278065639, 3621216949, 2880169549, 1987484396, 3402253711, 2189597983, 3385409673, 2105378810, 4210693615, 1499065266, 1195886990, 4042263547, 2913856577, 3570689971, 2728590687, 2947541573, 2627518243, 2762274643, 1920112356, 3233831835, 3082273397, 4261223649, 2475929149, 640051788, 909531756, 1061110142, 4160160501, 3435941763, 875846760, 2779116625, 3857003729, 4059105529, 1903268834, 3638064043, 825316194, 353713962, 67374088, 3351728789, 589522246, 3284360861, 404236336, 2526454071, 84217610, 2593830191, 117901582, 303183396, 2155911963, 3806477791, 3958056653, 656894286, 2998062463, 1970642922, 151591698, 2206440989, 741110872, 437923380, 454765878, 1852748508, 1515908788, 2694904667, 1381168804, 993742198, 3604373943, 3014905469, 690584402, 3823320797, 791638366, 2223281939, 1398011302, 3520161977, 0, 3991743681, 538992704, 4244381667, 2981218425, 1532751286, 1785380564, 3419096717, 3200178535, 960056178, 1246420628, 1280103576, 1482221744, 3486468741, 3503319995, 4025428677, 2863326543, 4227536621, 1128514950, 1296947098, 859002214, 2240123921, 1162203018, 4193849577, 33687044, 2139062782, 1347481760, 1010582648, 2678045221, 2829640523, 1364325282, 2745433693, 1077985408, 2408548869, 2459086143, 2644360225, 943212656, 4126475505, 3166494563, 3065430391, 3671750063, 555836226, 269496352, 4294908645, 4092792573, 3537006015, 3452783745, 202118168, 320025894, 3974901699, 1600119230, 2543297077, 1145359496, 387397934, 3301201811, 2812801621, 2122220284, 1027426170, 1684319432, 1566435258, 421079858, 1936954854, 1616945344, 2172753945, 1330631070, 3705438115, 572679748, 707427924, 2425400123, 2290647819, 1179044492, 4008585671, 3099120491, 336870440, 3739122087, 1583276732, 185277718, 3688593069, 3772791771, 842159716, 976899700, 168435220, 1229577106, 101059084, 606366792, 1549591736, 3267517855, 3553849021, 2897014595, 1650632388, 2442242105, 2509612081, 3840161747, 2038008818, 3890688725, 3368567691, 926374254, 1835907034, 2374863873, 3587531953, 1313788572, 2846482505, 1819063512, 1448540844, 4109633523, 3941213647, 1701162954, 2054852340, 2930698567, 134748176, 3132806511, 2021165296, 623210314, 774795868, 471606328, 2795958615, 3031746419, 3334885783, 3907527627, 3722280097, 1953799400, 522133822, 1263263126, 3183336545, 2341176845, 2324333839, 1886425312, 1044267644, 3048588401, 1718004428, 1212733584, 50529542, 4143317495, 235803164, 1633788866, 892690282, 1465383342, 3115962473, 2256965911, 3250673817, 488449850, 2661202215, 3789633753, 4177007595, 2560144171, 286339874, 1768537042, 3654906025, 2391705863, 2492770099, 2610673197, 505291324, 2273808917, 3924369609, 3469625735, 1431699370, 673740880, 3755965093, 2358021891, 2711746649, 2307489801, 218961690, 3217021541, 3873845719, 1111672452, 1751693520, 1094828930, 2576986153, 757954394, 252645662, 2964376443, 1414855848, 3149649517, 370555436];
-        var T5 = [1374988112, 2118214995, 437757123, 975658646, 1001089995, 530400753, 2902087851, 1273168787, 540080725, 2910219766, 2295101073, 4110568485, 1340463100, 3307916247, 641025152, 3043140495, 3736164937, 632953703, 1172967064, 1576976609, 3274667266, 2169303058, 2370213795, 1809054150, 59727847, 361929877, 3211623147, 2505202138, 3569255213, 1484005843, 1239443753, 2395588676, 1975683434, 4102977912, 2572697195, 666464733, 3202437046, 4035489047, 3374361702, 2110667444, 1675577880, 3843699074, 2538681184, 1649639237, 2976151520, 3144396420, 4269907996, 4178062228, 1883793496, 2403728665, 2497604743, 1383856311, 2876494627, 1917518562, 3810496343, 1716890410, 3001755655, 800440835, 2261089178, 3543599269, 807962610, 599762354, 33778362, 3977675356, 2328828971, 2809771154, 4077384432, 1315562145, 1708848333, 101039829, 3509871135, 3299278474, 875451293, 2733856160, 92987698, 2767645557, 193195065, 1080094634, 1584504582, 3178106961, 1042385657, 2531067453, 3711829422, 1306967366, 2438237621, 1908694277, 67556463, 1615861247, 429456164, 3602770327, 2302690252, 1742315127, 2968011453, 126454664, 3877198648, 2043211483, 2709260871, 2084704233, 4169408201, 0, 159417987, 841739592, 504459436, 1817866830, 4245618683, 260388950, 1034867998, 908933415, 168810852, 1750902305, 2606453969, 607530554, 202008497, 2472011535, 3035535058, 463180190, 2160117071, 1641816226, 1517767529, 470948374, 3801332234, 3231722213, 1008918595, 303765277, 235474187, 4069246893, 766945465, 337553864, 1475418501, 2943682380, 4003061179, 2743034109, 4144047775, 1551037884, 1147550661, 1543208500, 2336434550, 3408119516, 3069049960, 3102011747, 3610369226, 1113818384, 328671808, 2227573024, 2236228733, 3535486456, 2935566865, 3341394285, 496906059, 3702665459, 226906860, 2009195472, 733156972, 2842737049, 294930682, 1206477858, 2835123396, 2700099354, 1451044056, 573804783, 2269728455, 3644379585, 2362090238, 2564033334, 2801107407, 2776292904, 3669462566, 1068351396, 742039012, 1350078989, 1784663195, 1417561698, 4136440770, 2430122216, 775550814, 2193862645, 2673705150, 1775276924, 1876241833, 3475313331, 3366754619, 270040487, 3902563182, 3678124923, 3441850377, 1851332852, 3969562369, 2203032232, 3868552805, 2868897406, 566021896, 4011190502, 3135740889, 1248802510, 3936291284, 699432150, 832877231, 708780849, 3332740144, 899835584, 1951317047, 4236429990, 3767586992, 866637845, 4043610186, 1106041591, 2144161806, 395441711, 1984812685, 1139781709, 3433712980, 3835036895, 2664543715, 1282050075, 3240894392, 1181045119, 2640243204, 25965917, 4203181171, 4211818798, 3009879386, 2463879762, 3910161971, 1842759443, 2597806476, 933301370, 1509430414, 3943906441, 3467192302, 3076639029, 3776767469, 2051518780, 2631065433, 1441952575, 404016761, 1942435775, 1408749034, 1610459739, 3745345300, 2017778566, 3400528769, 3110650942, 941896748, 3265478751, 371049330, 3168937228, 675039627, 4279080257, 967311729, 135050206, 3635733660, 1683407248, 2076935265, 3576870512, 1215061108, 3501741890];
-        var T6 = [1347548327, 1400783205, 3273267108, 2520393566, 3409685355, 4045380933, 2880240216, 2471224067, 1428173050, 4138563181, 2441661558, 636813900, 4233094615, 3620022987, 2149987652, 2411029155, 1239331162, 1730525723, 2554718734, 3781033664, 46346101, 310463728, 2743944855, 3328955385, 3875770207, 2501218972, 3955191162, 3667219033, 768917123, 3545789473, 692707433, 1150208456, 1786102409, 2029293177, 1805211710, 3710368113, 3065962831, 401639597, 1724457132, 3028143674, 409198410, 2196052529, 1620529459, 1164071807, 3769721975, 2226875310, 486441376, 2499348523, 1483753576, 428819965, 2274680428, 3075636216, 598438867, 3799141122, 1474502543, 711349675, 129166120, 53458370, 2592523643, 2782082824, 4063242375, 2988687269, 3120694122, 1559041666, 730517276, 2460449204, 4042459122, 2706270690, 3446004468, 3573941694, 533804130, 2328143614, 2637442643, 2695033685, 839224033, 1973745387, 957055980, 2856345839, 106852767, 1371368976, 4181598602, 1033297158, 2933734917, 1179510461, 3046200461, 91341917, 1862534868, 4284502037, 605657339, 2547432937, 3431546947, 2003294622, 3182487618, 2282195339, 954669403, 3682191598, 1201765386, 3917234703, 3388507166, 0, 2198438022, 1211247597, 2887651696, 1315723890, 4227665663, 1443857720, 507358933, 657861945, 1678381017, 560487590, 3516619604, 975451694, 2970356327, 261314535, 3535072918, 2652609425, 1333838021, 2724322336, 1767536459, 370938394, 182621114, 3854606378, 1128014560, 487725847, 185469197, 2918353863, 3106780840, 3356761769, 2237133081, 1286567175, 3152976349, 4255350624, 2683765030, 3160175349, 3309594171, 878443390, 1988838185, 3704300486, 1756818940, 1673061617, 3403100636, 272786309, 1075025698, 545572369, 2105887268, 4174560061, 296679730, 1841768865, 1260232239, 4091327024, 3960309330, 3497509347, 1814803222, 2578018489, 4195456072, 575138148, 3299409036, 446754879, 3629546796, 4011996048, 3347532110, 3252238545, 4270639778, 915985419, 3483825537, 681933534, 651868046, 2755636671, 3828103837, 223377554, 2607439820, 1649704518, 3270937875, 3901806776, 1580087799, 4118987695, 3198115200, 2087309459, 2842678573, 3016697106, 1003007129, 2802849917, 1860738147, 2077965243, 164439672, 4100872472, 32283319, 2827177882, 1709610350, 2125135846, 136428751, 3874428392, 3652904859, 3460984630, 3572145929, 3593056380, 2939266226, 824852259, 818324884, 3224740454, 930369212, 2801566410, 2967507152, 355706840, 1257309336, 4148292826, 243256656, 790073846, 2373340630, 1296297904, 1422699085, 3756299780, 3818836405, 457992840, 3099667487, 2135319889, 77422314, 1560382517, 1945798516, 788204353, 1521706781, 1385356242, 870912086, 325965383, 2358957921, 2050466060, 2388260884, 2313884476, 4006521127, 901210569, 3990953189, 1014646705, 1503449823, 1062597235, 2031621326, 3212035895, 3931371469, 1533017514, 350174575, 2256028891, 2177544179, 1052338372, 741876788, 1606591296, 1914052035, 213705253, 2334669897, 1107234197, 1899603969, 3725069491, 2631447780, 2422494913, 1635502980, 1893020342, 1950903388, 1120974935];
-        var T7 = [2807058932, 1699970625, 2764249623, 1586903591, 1808481195, 1173430173, 1487645946, 59984867, 4199882800, 1844882806, 1989249228, 1277555970, 3623636965, 3419915562, 1149249077, 2744104290, 1514790577, 459744698, 244860394, 3235995134, 1963115311, 4027744588, 2544078150, 4190530515, 1608975247, 2627016082, 2062270317, 1507497298, 2200818878, 567498868, 1764313568, 3359936201, 2305455554, 2037970062, 1047239e3, 1910319033, 1337376481, 2904027272, 2892417312, 984907214, 1243112415, 830661914, 861968209, 2135253587, 2011214180, 2927934315, 2686254721, 731183368, 1750626376, 4246310725, 1820824798, 4172763771, 3542330227, 48394827, 2404901663, 2871682645, 671593195, 3254988725, 2073724613, 145085239, 2280796200, 2779915199, 1790575107, 2187128086, 472615631, 3029510009, 4075877127, 3802222185, 4107101658, 3201631749, 1646252340, 4270507174, 1402811438, 1436590835, 3778151818, 3950355702, 3963161475, 4020912224, 2667994737, 273792366, 2331590177, 104699613, 95345982, 3175501286, 2377486676, 1560637892, 3564045318, 369057872, 4213447064, 3919042237, 1137477952, 2658625497, 1119727848, 2340947849, 1530455833, 4007360968, 172466556, 266959938, 516552836, 0, 2256734592, 3980931627, 1890328081, 1917742170, 4294704398, 945164165, 3575528878, 958871085, 3647212047, 2787207260, 1423022939, 775562294, 1739656202, 3876557655, 2530391278, 2443058075, 3310321856, 547512796, 1265195639, 437656594, 3121275539, 719700128, 3762502690, 387781147, 218828297, 3350065803, 2830708150, 2848461854, 428169201, 122466165, 3720081049, 1627235199, 648017665, 4122762354, 1002783846, 2117360635, 695634755, 3336358691, 4234721005, 4049844452, 3704280881, 2232435299, 574624663, 287343814, 612205898, 1039717051, 840019705, 2708326185, 793451934, 821288114, 1391201670, 3822090177, 376187827, 3113855344, 1224348052, 1679968233, 2361698556, 1058709744, 752375421, 2431590963, 1321699145, 3519142200, 2734591178, 188127444, 2177869557, 3727205754, 2384911031, 3215212461, 2648976442, 2450346104, 3432737375, 1180849278, 331544205, 3102249176, 4150144569, 2952102595, 2159976285, 2474404304, 766078933, 313773861, 2570832044, 2108100632, 1668212892, 3145456443, 2013908262, 418672217, 3070356634, 2594734927, 1852171925, 3867060991, 3473416636, 3907448597, 2614737639, 919489135, 164948639, 2094410160, 2997825956, 590424639, 2486224549, 1723872674, 3157750862, 3399941250, 3501252752, 3625268135, 2555048196, 3673637356, 1343127501, 4130281361, 3599595085, 2957853679, 1297403050, 81781910, 3051593425, 2283490410, 532201772, 1367295589, 3926170974, 895287692, 1953757831, 1093597963, 492483431, 3528626907, 1446242576, 1192455638, 1636604631, 209336225, 344873464, 1015671571, 669961897, 3375740769, 3857572124, 2973530695, 3747192018, 1933530610, 3464042516, 935293895, 3454686199, 2858115069, 1863638845, 3683022916, 4085369519, 3292445032, 875313188, 1080017571, 3279033885, 621591778, 1233856572, 2504130317, 24197544, 3017672716, 3835484340, 3247465558, 2220981195, 3060847922, 1551124588, 1463996600];
-        var T8 = [4104605777, 1097159550, 396673818, 660510266, 2875968315, 2638606623, 4200115116, 3808662347, 821712160, 1986918061, 3430322568, 38544885, 3856137295, 718002117, 893681702, 1654886325, 2975484382, 3122358053, 3926825029, 4274053469, 796197571, 1290801793, 1184342925, 3556361835, 2405426947, 2459735317, 1836772287, 1381620373, 3196267988, 1948373848, 3764988233, 3385345166, 3263785589, 2390325492, 1480485785, 3111247143, 3780097726, 2293045232, 548169417, 3459953789, 3746175075, 439452389, 1362321559, 1400849762, 1685577905, 1806599355, 2174754046, 137073913, 1214797936, 1174215055, 3731654548, 2079897426, 1943217067, 1258480242, 529487843, 1437280870, 3945269170, 3049390895, 3313212038, 923313619, 679998e3, 3215307299, 57326082, 377642221, 3474729866, 2041877159, 133361907, 1776460110, 3673476453, 96392454, 878845905, 2801699524, 777231668, 4082475170, 2330014213, 4142626212, 2213296395, 1626319424, 1906247262, 1846563261, 562755902, 3708173718, 1040559837, 3871163981, 1418573201, 3294430577, 114585348, 1343618912, 2566595609, 3186202582, 1078185097, 3651041127, 3896688048, 2307622919, 425408743, 3371096953, 2081048481, 1108339068, 2216610296, 0, 2156299017, 736970802, 292596766, 1517440620, 251657213, 2235061775, 2933202493, 758720310, 265905162, 1554391400, 1532285339, 908999204, 174567692, 1474760595, 4002861748, 2610011675, 3234156416, 3693126241, 2001430874, 303699484, 2478443234, 2687165888, 585122620, 454499602, 151849742, 2345119218, 3064510765, 514443284, 4044981591, 1963412655, 2581445614, 2137062819, 19308535, 1928707164, 1715193156, 4219352155, 1126790795, 600235211, 3992742070, 3841024952, 836553431, 1669664834, 2535604243, 3323011204, 1243905413, 3141400786, 4180808110, 698445255, 2653899549, 2989552604, 2253581325, 3252932727, 3004591147, 1891211689, 2487810577, 3915653703, 4237083816, 4030667424, 2100090966, 865136418, 1229899655, 953270745, 3399679628, 3557504664, 4118925222, 2061379749, 3079546586, 2915017791, 983426092, 2022837584, 1607244650, 2118541908, 2366882550, 3635996816, 972512814, 3283088770, 1568718495, 3499326569, 3576539503, 621982671, 2895723464, 410887952, 2623762152, 1002142683, 645401037, 1494807662, 2595684844, 1335535747, 2507040230, 4293295786, 3167684641, 367585007, 3885750714, 1865862730, 2668221674, 2960971305, 2763173681, 1059270954, 2777952454, 2724642869, 1320957812, 2194319100, 2429595872, 2815956275, 77089521, 3973773121, 3444575871, 2448830231, 1305906550, 4021308739, 2857194700, 2516901860, 3518358430, 1787304780, 740276417, 1699839814, 1592394909, 2352307457, 2272556026, 188821243, 1729977011, 3687994002, 274084841, 3594982253, 3613494426, 2701949495, 4162096729, 322734571, 2837966542, 1640576439, 484830689, 1202797690, 3537852828, 4067639125, 349075736, 3342319475, 4157467219, 4255800159, 1030690015, 1155237496, 2951971274, 1757691577, 607398968, 2738905026, 499347990, 3794078908, 1011452712, 227885567, 2818666809, 213114376, 3034881240, 1455525988, 3414450555, 850817237, 1817998408, 3092726480];
-        var U1 = [0, 235474187, 470948374, 303765277, 941896748, 908933415, 607530554, 708780849, 1883793496, 2118214995, 1817866830, 1649639237, 1215061108, 1181045119, 1417561698, 1517767529, 3767586992, 4003061179, 4236429990, 4069246893, 3635733660, 3602770327, 3299278474, 3400528769, 2430122216, 2664543715, 2362090238, 2193862645, 2835123396, 2801107407, 3035535058, 3135740889, 3678124923, 3576870512, 3341394285, 3374361702, 3810496343, 3977675356, 4279080257, 4043610186, 2876494627, 2776292904, 3076639029, 3110650942, 2472011535, 2640243204, 2403728665, 2169303058, 1001089995, 899835584, 666464733, 699432150, 59727847, 226906860, 530400753, 294930682, 1273168787, 1172967064, 1475418501, 1509430414, 1942435775, 2110667444, 1876241833, 1641816226, 2910219766, 2743034109, 2976151520, 3211623147, 2505202138, 2606453969, 2302690252, 2269728455, 3711829422, 3543599269, 3240894392, 3475313331, 3843699074, 3943906441, 4178062228, 4144047775, 1306967366, 1139781709, 1374988112, 1610459739, 1975683434, 2076935265, 1775276924, 1742315127, 1034867998, 866637845, 566021896, 800440835, 92987698, 193195065, 429456164, 395441711, 1984812685, 2017778566, 1784663195, 1683407248, 1315562145, 1080094634, 1383856311, 1551037884, 101039829, 135050206, 437757123, 337553864, 1042385657, 807962610, 573804783, 742039012, 2531067453, 2564033334, 2328828971, 2227573024, 2935566865, 2700099354, 3001755655, 3168937228, 3868552805, 3902563182, 4203181171, 4102977912, 3736164937, 3501741890, 3265478751, 3433712980, 1106041591, 1340463100, 1576976609, 1408749034, 2043211483, 2009195472, 1708848333, 1809054150, 832877231, 1068351396, 766945465, 599762354, 159417987, 126454664, 361929877, 463180190, 2709260871, 2943682380, 3178106961, 3009879386, 2572697195, 2538681184, 2236228733, 2336434550, 3509871135, 3745345300, 3441850377, 3274667266, 3910161971, 3877198648, 4110568485, 4211818798, 2597806476, 2497604743, 2261089178, 2295101073, 2733856160, 2902087851, 3202437046, 2968011453, 3936291284, 3835036895, 4136440770, 4169408201, 3535486456, 3702665459, 3467192302, 3231722213, 2051518780, 1951317047, 1716890410, 1750902305, 1113818384, 1282050075, 1584504582, 1350078989, 168810852, 67556463, 371049330, 404016761, 841739592, 1008918595, 775550814, 540080725, 3969562369, 3801332234, 4035489047, 4269907996, 3569255213, 3669462566, 3366754619, 3332740144, 2631065433, 2463879762, 2160117071, 2395588676, 2767645557, 2868897406, 3102011747, 3069049960, 202008497, 33778362, 270040487, 504459436, 875451293, 975658646, 675039627, 641025152, 2084704233, 1917518562, 1615861247, 1851332852, 1147550661, 1248802510, 1484005843, 1451044056, 933301370, 967311729, 733156972, 632953703, 260388950, 25965917, 328671808, 496906059, 1206477858, 1239443753, 1543208500, 1441952575, 2144161806, 1908694277, 1675577880, 1842759443, 3610369226, 3644379585, 3408119516, 3307916247, 4011190502, 3776767469, 4077384432, 4245618683, 2809771154, 2842737049, 3144396420, 3043140495, 2673705150, 2438237621, 2203032232, 2370213795];
-        var U2 = [0, 185469197, 370938394, 487725847, 741876788, 657861945, 975451694, 824852259, 1483753576, 1400783205, 1315723890, 1164071807, 1950903388, 2135319889, 1649704518, 1767536459, 2967507152, 3152976349, 2801566410, 2918353863, 2631447780, 2547432937, 2328143614, 2177544179, 3901806776, 3818836405, 4270639778, 4118987695, 3299409036, 3483825537, 3535072918, 3652904859, 2077965243, 1893020342, 1841768865, 1724457132, 1474502543, 1559041666, 1107234197, 1257309336, 598438867, 681933534, 901210569, 1052338372, 261314535, 77422314, 428819965, 310463728, 3409685355, 3224740454, 3710368113, 3593056380, 3875770207, 3960309330, 4045380933, 4195456072, 2471224067, 2554718734, 2237133081, 2388260884, 3212035895, 3028143674, 2842678573, 2724322336, 4138563181, 4255350624, 3769721975, 3955191162, 3667219033, 3516619604, 3431546947, 3347532110, 2933734917, 2782082824, 3099667487, 3016697106, 2196052529, 2313884476, 2499348523, 2683765030, 1179510461, 1296297904, 1347548327, 1533017514, 1786102409, 1635502980, 2087309459, 2003294622, 507358933, 355706840, 136428751, 53458370, 839224033, 957055980, 605657339, 790073846, 2373340630, 2256028891, 2607439820, 2422494913, 2706270690, 2856345839, 3075636216, 3160175349, 3573941694, 3725069491, 3273267108, 3356761769, 4181598602, 4063242375, 4011996048, 3828103837, 1033297158, 915985419, 730517276, 545572369, 296679730, 446754879, 129166120, 213705253, 1709610350, 1860738147, 1945798516, 2029293177, 1239331162, 1120974935, 1606591296, 1422699085, 4148292826, 4233094615, 3781033664, 3931371469, 3682191598, 3497509347, 3446004468, 3328955385, 2939266226, 2755636671, 3106780840, 2988687269, 2198438022, 2282195339, 2501218972, 2652609425, 1201765386, 1286567175, 1371368976, 1521706781, 1805211710, 1620529459, 2105887268, 1988838185, 533804130, 350174575, 164439672, 46346101, 870912086, 954669403, 636813900, 788204353, 2358957921, 2274680428, 2592523643, 2441661558, 2695033685, 2880240216, 3065962831, 3182487618, 3572145929, 3756299780, 3270937875, 3388507166, 4174560061, 4091327024, 4006521127, 3854606378, 1014646705, 930369212, 711349675, 560487590, 272786309, 457992840, 106852767, 223377554, 1678381017, 1862534868, 1914052035, 2031621326, 1211247597, 1128014560, 1580087799, 1428173050, 32283319, 182621114, 401639597, 486441376, 768917123, 651868046, 1003007129, 818324884, 1503449823, 1385356242, 1333838021, 1150208456, 1973745387, 2125135846, 1673061617, 1756818940, 2970356327, 3120694122, 2802849917, 2887651696, 2637442643, 2520393566, 2334669897, 2149987652, 3917234703, 3799141122, 4284502037, 4100872472, 3309594171, 3460984630, 3545789473, 3629546796, 2050466060, 1899603969, 1814803222, 1730525723, 1443857720, 1560382517, 1075025698, 1260232239, 575138148, 692707433, 878443390, 1062597235, 243256656, 91341917, 409198410, 325965383, 3403100636, 3252238545, 3704300486, 3620022987, 3874428392, 3990953189, 4042459122, 4227665663, 2460449204, 2578018489, 2226875310, 2411029155, 3198115200, 3046200461, 2827177882, 2743944855];
-        var U3 = [0, 218828297, 437656594, 387781147, 875313188, 958871085, 775562294, 590424639, 1750626376, 1699970625, 1917742170, 2135253587, 1551124588, 1367295589, 1180849278, 1265195639, 3501252752, 3720081049, 3399941250, 3350065803, 3835484340, 3919042237, 4270507174, 4085369519, 3102249176, 3051593425, 2734591178, 2952102595, 2361698556, 2177869557, 2530391278, 2614737639, 3145456443, 3060847922, 2708326185, 2892417312, 2404901663, 2187128086, 2504130317, 2555048196, 3542330227, 3727205754, 3375740769, 3292445032, 3876557655, 3926170974, 4246310725, 4027744588, 1808481195, 1723872674, 1910319033, 2094410160, 1608975247, 1391201670, 1173430173, 1224348052, 59984867, 244860394, 428169201, 344873464, 935293895, 984907214, 766078933, 547512796, 1844882806, 1627235199, 2011214180, 2062270317, 1507497298, 1423022939, 1137477952, 1321699145, 95345982, 145085239, 532201772, 313773861, 830661914, 1015671571, 731183368, 648017665, 3175501286, 2957853679, 2807058932, 2858115069, 2305455554, 2220981195, 2474404304, 2658625497, 3575528878, 3625268135, 3473416636, 3254988725, 3778151818, 3963161475, 4213447064, 4130281361, 3599595085, 3683022916, 3432737375, 3247465558, 3802222185, 4020912224, 4172763771, 4122762354, 3201631749, 3017672716, 2764249623, 2848461854, 2331590177, 2280796200, 2431590963, 2648976442, 104699613, 188127444, 472615631, 287343814, 840019705, 1058709744, 671593195, 621591778, 1852171925, 1668212892, 1953757831, 2037970062, 1514790577, 1463996600, 1080017571, 1297403050, 3673637356, 3623636965, 3235995134, 3454686199, 4007360968, 3822090177, 4107101658, 4190530515, 2997825956, 3215212461, 2830708150, 2779915199, 2256734592, 2340947849, 2627016082, 2443058075, 172466556, 122466165, 273792366, 492483431, 1047239e3, 861968209, 612205898, 695634755, 1646252340, 1863638845, 2013908262, 1963115311, 1446242576, 1530455833, 1277555970, 1093597963, 1636604631, 1820824798, 2073724613, 1989249228, 1436590835, 1487645946, 1337376481, 1119727848, 164948639, 81781910, 331544205, 516552836, 1039717051, 821288114, 669961897, 719700128, 2973530695, 3157750862, 2871682645, 2787207260, 2232435299, 2283490410, 2667994737, 2450346104, 3647212047, 3564045318, 3279033885, 3464042516, 3980931627, 3762502690, 4150144569, 4199882800, 3070356634, 3121275539, 2904027272, 2686254721, 2200818878, 2384911031, 2570832044, 2486224549, 3747192018, 3528626907, 3310321856, 3359936201, 3950355702, 3867060991, 4049844452, 4234721005, 1739656202, 1790575107, 2108100632, 1890328081, 1402811438, 1586903591, 1233856572, 1149249077, 266959938, 48394827, 369057872, 418672217, 1002783846, 919489135, 567498868, 752375421, 209336225, 24197544, 376187827, 459744698, 945164165, 895287692, 574624663, 793451934, 1679968233, 1764313568, 2117360635, 1933530610, 1343127501, 1560637892, 1243112415, 1192455638, 3704280881, 3519142200, 3336358691, 3419915562, 3907448597, 3857572124, 4075877127, 4294704398, 3029510009, 3113855344, 2927934315, 2744104290, 2159976285, 2377486676, 2594734927, 2544078150];
-        var U4 = [0, 151849742, 303699484, 454499602, 607398968, 758720310, 908999204, 1059270954, 1214797936, 1097159550, 1517440620, 1400849762, 1817998408, 1699839814, 2118541908, 2001430874, 2429595872, 2581445614, 2194319100, 2345119218, 3034881240, 3186202582, 2801699524, 2951971274, 3635996816, 3518358430, 3399679628, 3283088770, 4237083816, 4118925222, 4002861748, 3885750714, 1002142683, 850817237, 698445255, 548169417, 529487843, 377642221, 227885567, 77089521, 1943217067, 2061379749, 1640576439, 1757691577, 1474760595, 1592394909, 1174215055, 1290801793, 2875968315, 2724642869, 3111247143, 2960971305, 2405426947, 2253581325, 2638606623, 2487810577, 3808662347, 3926825029, 4044981591, 4162096729, 3342319475, 3459953789, 3576539503, 3693126241, 1986918061, 2137062819, 1685577905, 1836772287, 1381620373, 1532285339, 1078185097, 1229899655, 1040559837, 923313619, 740276417, 621982671, 439452389, 322734571, 137073913, 19308535, 3871163981, 4021308739, 4104605777, 4255800159, 3263785589, 3414450555, 3499326569, 3651041127, 2933202493, 2815956275, 3167684641, 3049390895, 2330014213, 2213296395, 2566595609, 2448830231, 1305906550, 1155237496, 1607244650, 1455525988, 1776460110, 1626319424, 2079897426, 1928707164, 96392454, 213114376, 396673818, 514443284, 562755902, 679998e3, 865136418, 983426092, 3708173718, 3557504664, 3474729866, 3323011204, 4180808110, 4030667424, 3945269170, 3794078908, 2507040230, 2623762152, 2272556026, 2390325492, 2975484382, 3092726480, 2738905026, 2857194700, 3973773121, 3856137295, 4274053469, 4157467219, 3371096953, 3252932727, 3673476453, 3556361835, 2763173681, 2915017791, 3064510765, 3215307299, 2156299017, 2307622919, 2459735317, 2610011675, 2081048481, 1963412655, 1846563261, 1729977011, 1480485785, 1362321559, 1243905413, 1126790795, 878845905, 1030690015, 645401037, 796197571, 274084841, 425408743, 38544885, 188821243, 3613494426, 3731654548, 3313212038, 3430322568, 4082475170, 4200115116, 3780097726, 3896688048, 2668221674, 2516901860, 2366882550, 2216610296, 3141400786, 2989552604, 2837966542, 2687165888, 1202797690, 1320957812, 1437280870, 1554391400, 1669664834, 1787304780, 1906247262, 2022837584, 265905162, 114585348, 499347990, 349075736, 736970802, 585122620, 972512814, 821712160, 2595684844, 2478443234, 2293045232, 2174754046, 3196267988, 3079546586, 2895723464, 2777952454, 3537852828, 3687994002, 3234156416, 3385345166, 4142626212, 4293295786, 3841024952, 3992742070, 174567692, 57326082, 410887952, 292596766, 777231668, 660510266, 1011452712, 893681702, 1108339068, 1258480242, 1343618912, 1494807662, 1715193156, 1865862730, 1948373848, 2100090966, 2701949495, 2818666809, 3004591147, 3122358053, 2235061775, 2352307457, 2535604243, 2653899549, 3915653703, 3764988233, 4219352155, 4067639125, 3444575871, 3294430577, 3746175075, 3594982253, 836553431, 953270745, 600235211, 718002117, 367585007, 484830689, 133361907, 251657213, 2041877159, 1891211689, 1806599355, 1654886325, 1568718495, 1418573201, 1335535747, 1184342925];
-        function convertToInt32(bytes) {
-          var result = [];
-          for (var i2 = 0; i2 < bytes.length; i2 += 4) {
-            result.push(
-              bytes[i2] << 24 | bytes[i2 + 1] << 16 | bytes[i2 + 2] << 8 | bytes[i2 + 3]
-            );
-          }
-          return result;
-        }
-        var AES = function(key) {
-          if (!(this instanceof AES)) {
-            throw Error("AES must be instanitated with `new`");
-          }
-          Object.defineProperty(this, "key", {
-            value: coerceArray(key, true)
-          });
-          this._prepare();
-        };
-        AES.prototype._prepare = function() {
-          var rounds = numberOfRounds[this.key.length];
-          if (rounds == null) {
-            throw new Error("invalid key size (must be 16, 24 or 32 bytes)");
-          }
-          this._Ke = [];
-          this._Kd = [];
-          for (var i2 = 0; i2 <= rounds; i2++) {
-            this._Ke.push([0, 0, 0, 0]);
-            this._Kd.push([0, 0, 0, 0]);
-          }
-          var roundKeyCount = (rounds + 1) * 4;
-          var KC = this.key.length / 4;
-          var tk = convertToInt32(this.key);
-          var index;
-          for (var i2 = 0; i2 < KC; i2++) {
-            index = i2 >> 2;
-            this._Ke[index][i2 % 4] = tk[i2];
-            this._Kd[rounds - index][i2 % 4] = tk[i2];
-          }
-          var rconpointer = 0;
-          var t = KC, tt;
-          while (t < roundKeyCount) {
-            tt = tk[KC - 1];
-            tk[0] ^= S[tt >> 16 & 255] << 24 ^ S[tt >> 8 & 255] << 16 ^ S[tt & 255] << 8 ^ S[tt >> 24 & 255] ^ rcon[rconpointer] << 24;
-            rconpointer += 1;
-            if (KC != 8) {
-              for (var i2 = 1; i2 < KC; i2++) {
-                tk[i2] ^= tk[i2 - 1];
-              }
-            } else {
-              for (var i2 = 1; i2 < KC / 2; i2++) {
-                tk[i2] ^= tk[i2 - 1];
-              }
-              tt = tk[KC / 2 - 1];
-              tk[KC / 2] ^= S[tt & 255] ^ S[tt >> 8 & 255] << 8 ^ S[tt >> 16 & 255] << 16 ^ S[tt >> 24 & 255] << 24;
-              for (var i2 = KC / 2 + 1; i2 < KC; i2++) {
-                tk[i2] ^= tk[i2 - 1];
-              }
-            }
-            var i2 = 0, r, c;
-            while (i2 < KC && t < roundKeyCount) {
-              r = t >> 2;
-              c = t % 4;
-              this._Ke[r][c] = tk[i2];
-              this._Kd[rounds - r][c] = tk[i2++];
-              t++;
-            }
-          }
-          for (var r = 1; r < rounds; r++) {
-            for (var c = 0; c < 4; c++) {
-              tt = this._Kd[r][c];
-              this._Kd[r][c] = U1[tt >> 24 & 255] ^ U2[tt >> 16 & 255] ^ U3[tt >> 8 & 255] ^ U4[tt & 255];
-            }
-          }
-        };
-        AES.prototype.encrypt = function(plaintext) {
-          if (plaintext.length != 16) {
-            throw new Error("invalid plaintext size (must be 16 bytes)");
-          }
-          var rounds = this._Ke.length - 1;
-          var a = [0, 0, 0, 0];
-          var t = convertToInt32(plaintext);
-          for (var i2 = 0; i2 < 4; i2++) {
-            t[i2] ^= this._Ke[0][i2];
-          }
-          for (var r = 1; r < rounds; r++) {
-            for (var i2 = 0; i2 < 4; i2++) {
-              a[i2] = T1[t[i2] >> 24 & 255] ^ T2[t[(i2 + 1) % 4] >> 16 & 255] ^ T3[t[(i2 + 2) % 4] >> 8 & 255] ^ T4[t[(i2 + 3) % 4] & 255] ^ this._Ke[r][i2];
-            }
-            t = a.slice();
-          }
-          var result = createArray(16), tt;
-          for (var i2 = 0; i2 < 4; i2++) {
-            tt = this._Ke[rounds][i2];
-            result[4 * i2] = (S[t[i2] >> 24 & 255] ^ tt >> 24) & 255;
-            result[4 * i2 + 1] = (S[t[(i2 + 1) % 4] >> 16 & 255] ^ tt >> 16) & 255;
-            result[4 * i2 + 2] = (S[t[(i2 + 2) % 4] >> 8 & 255] ^ tt >> 8) & 255;
-            result[4 * i2 + 3] = (S[t[(i2 + 3) % 4] & 255] ^ tt) & 255;
-          }
-          return result;
-        };
-        AES.prototype.decrypt = function(ciphertext) {
-          if (ciphertext.length != 16) {
-            throw new Error("invalid ciphertext size (must be 16 bytes)");
-          }
-          var rounds = this._Kd.length - 1;
-          var a = [0, 0, 0, 0];
-          var t = convertToInt32(ciphertext);
-          for (var i2 = 0; i2 < 4; i2++) {
-            t[i2] ^= this._Kd[0][i2];
-          }
-          for (var r = 1; r < rounds; r++) {
-            for (var i2 = 0; i2 < 4; i2++) {
-              a[i2] = T5[t[i2] >> 24 & 255] ^ T6[t[(i2 + 3) % 4] >> 16 & 255] ^ T7[t[(i2 + 2) % 4] >> 8 & 255] ^ T8[t[(i2 + 1) % 4] & 255] ^ this._Kd[r][i2];
-            }
-            t = a.slice();
-          }
-          var result = createArray(16), tt;
-          for (var i2 = 0; i2 < 4; i2++) {
-            tt = this._Kd[rounds][i2];
-            result[4 * i2] = (Si[t[i2] >> 24 & 255] ^ tt >> 24) & 255;
-            result[4 * i2 + 1] = (Si[t[(i2 + 3) % 4] >> 16 & 255] ^ tt >> 16) & 255;
-            result[4 * i2 + 2] = (Si[t[(i2 + 2) % 4] >> 8 & 255] ^ tt >> 8) & 255;
-            result[4 * i2 + 3] = (Si[t[(i2 + 1) % 4] & 255] ^ tt) & 255;
-          }
-          return result;
-        };
-        var ModeOfOperationECB = function(key) {
-          if (!(this instanceof ModeOfOperationECB)) {
-            throw Error("AES must be instanitated with `new`");
-          }
-          this.description = "Electronic Code Block";
-          this.name = "ecb";
-          this._aes = new AES(key);
-        };
-        ModeOfOperationECB.prototype.encrypt = function(plaintext) {
-          plaintext = coerceArray(plaintext);
-          if (plaintext.length % 16 !== 0) {
-            throw new Error("invalid plaintext size (must be multiple of 16 bytes)");
-          }
-          var ciphertext = createArray(plaintext.length);
-          var block2 = createArray(16);
-          for (var i2 = 0; i2 < plaintext.length; i2 += 16) {
-            copyArray(plaintext, block2, 0, i2, i2 + 16);
-            block2 = this._aes.encrypt(block2);
-            copyArray(block2, ciphertext, i2);
-          }
-          return ciphertext;
-        };
-        ModeOfOperationECB.prototype.decrypt = function(ciphertext) {
-          ciphertext = coerceArray(ciphertext);
-          if (ciphertext.length % 16 !== 0) {
-            throw new Error("invalid ciphertext size (must be multiple of 16 bytes)");
-          }
-          var plaintext = createArray(ciphertext.length);
-          var block2 = createArray(16);
-          for (var i2 = 0; i2 < ciphertext.length; i2 += 16) {
-            copyArray(ciphertext, block2, 0, i2, i2 + 16);
-            block2 = this._aes.decrypt(block2);
-            copyArray(block2, plaintext, i2);
-          }
-          return plaintext;
-        };
-        var ModeOfOperationCBC = function(key, iv) {
-          if (!(this instanceof ModeOfOperationCBC)) {
-            throw Error("AES must be instanitated with `new`");
-          }
-          this.description = "Cipher Block Chaining";
-          this.name = "cbc";
-          if (!iv) {
-            iv = createArray(16);
-          } else if (iv.length != 16) {
-            throw new Error("invalid initialation vector size (must be 16 bytes)");
-          }
-          this._lastCipherblock = coerceArray(iv, true);
-          this._aes = new AES(key);
-        };
-        ModeOfOperationCBC.prototype.encrypt = function(plaintext) {
-          plaintext = coerceArray(plaintext);
-          if (plaintext.length % 16 !== 0) {
-            throw new Error("invalid plaintext size (must be multiple of 16 bytes)");
-          }
-          var ciphertext = createArray(plaintext.length);
-          var block2 = createArray(16);
-          for (var i2 = 0; i2 < plaintext.length; i2 += 16) {
-            copyArray(plaintext, block2, 0, i2, i2 + 16);
-            for (var j2 = 0; j2 < 16; j2++) {
-              block2[j2] ^= this._lastCipherblock[j2];
-            }
-            this._lastCipherblock = this._aes.encrypt(block2);
-            copyArray(this._lastCipherblock, ciphertext, i2);
-          }
-          return ciphertext;
-        };
-        ModeOfOperationCBC.prototype.decrypt = function(ciphertext) {
-          ciphertext = coerceArray(ciphertext);
-          if (ciphertext.length % 16 !== 0) {
-            throw new Error("invalid ciphertext size (must be multiple of 16 bytes)");
-          }
-          var plaintext = createArray(ciphertext.length);
-          var block2 = createArray(16);
-          for (var i2 = 0; i2 < ciphertext.length; i2 += 16) {
-            copyArray(ciphertext, block2, 0, i2, i2 + 16);
-            block2 = this._aes.decrypt(block2);
-            for (var j2 = 0; j2 < 16; j2++) {
-              plaintext[i2 + j2] = block2[j2] ^ this._lastCipherblock[j2];
-            }
-            copyArray(ciphertext, this._lastCipherblock, 0, i2, i2 + 16);
-          }
-          return plaintext;
-        };
-        var ModeOfOperationCFB = function(key, iv, segmentSize) {
-          if (!(this instanceof ModeOfOperationCFB)) {
-            throw Error("AES must be instanitated with `new`");
-          }
-          this.description = "Cipher Feedback";
-          this.name = "cfb";
-          if (!iv) {
-            iv = createArray(16);
-          } else if (iv.length != 16) {
-            throw new Error("invalid initialation vector size (must be 16 size)");
-          }
-          if (!segmentSize) {
-            segmentSize = 1;
-          }
-          this.segmentSize = segmentSize;
-          this._shiftRegister = coerceArray(iv, true);
-          this._aes = new AES(key);
-        };
-        ModeOfOperationCFB.prototype.encrypt = function(plaintext) {
-          if (plaintext.length % this.segmentSize != 0) {
-            throw new Error("invalid plaintext size (must be segmentSize bytes)");
-          }
-          var encrypted = coerceArray(plaintext, true);
-          var xorSegment;
-          for (var i2 = 0; i2 < encrypted.length; i2 += this.segmentSize) {
-            xorSegment = this._aes.encrypt(this._shiftRegister);
-            for (var j2 = 0; j2 < this.segmentSize; j2++) {
-              encrypted[i2 + j2] ^= xorSegment[j2];
-            }
-            copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
-            copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i2, i2 + this.segmentSize);
-          }
-          return encrypted;
-        };
-        ModeOfOperationCFB.prototype.decrypt = function(ciphertext) {
-          if (ciphertext.length % this.segmentSize != 0) {
-            throw new Error("invalid ciphertext size (must be segmentSize bytes)");
-          }
-          var plaintext = coerceArray(ciphertext, true);
-          var xorSegment;
-          for (var i2 = 0; i2 < plaintext.length; i2 += this.segmentSize) {
-            xorSegment = this._aes.encrypt(this._shiftRegister);
-            for (var j2 = 0; j2 < this.segmentSize; j2++) {
-              plaintext[i2 + j2] ^= xorSegment[j2];
-            }
-            copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
-            copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i2, i2 + this.segmentSize);
-          }
-          return plaintext;
-        };
-        var ModeOfOperationOFB = function(key, iv) {
-          if (!(this instanceof ModeOfOperationOFB)) {
-            throw Error("AES must be instanitated with `new`");
-          }
-          this.description = "Output Feedback";
-          this.name = "ofb";
-          if (!iv) {
-            iv = createArray(16);
-          } else if (iv.length != 16) {
-            throw new Error("invalid initialation vector size (must be 16 bytes)");
-          }
-          this._lastPrecipher = coerceArray(iv, true);
-          this._lastPrecipherIndex = 16;
-          this._aes = new AES(key);
-        };
-        ModeOfOperationOFB.prototype.encrypt = function(plaintext) {
-          var encrypted = coerceArray(plaintext, true);
-          for (var i2 = 0; i2 < encrypted.length; i2++) {
-            if (this._lastPrecipherIndex === 16) {
-              this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
-              this._lastPrecipherIndex = 0;
-            }
-            encrypted[i2] ^= this._lastPrecipher[this._lastPrecipherIndex++];
-          }
-          return encrypted;
-        };
-        ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
-        var Counter = function(initialValue) {
-          if (!(this instanceof Counter)) {
-            throw Error("Counter must be instanitated with `new`");
-          }
-          if (initialValue !== 0 && !initialValue) {
-            initialValue = 1;
-          }
-          if (typeof initialValue === "number") {
-            this._counter = createArray(16);
-            this.setValue(initialValue);
-          } else {
-            this.setBytes(initialValue);
-          }
-        };
-        Counter.prototype.setValue = function(value) {
-          if (typeof value !== "number" || parseInt(value) != value) {
-            throw new Error("invalid counter value (must be an integer)");
-          }
-          if (value > Number.MAX_SAFE_INTEGER) {
-            throw new Error("integer value out of safe range");
-          }
-          for (var index = 15; index >= 0; --index) {
-            this._counter[index] = value % 256;
-            value = parseInt(value / 256);
-          }
-        };
-        Counter.prototype.setBytes = function(bytes) {
-          bytes = coerceArray(bytes, true);
-          if (bytes.length != 16) {
-            throw new Error("invalid counter bytes size (must be 16 bytes)");
-          }
-          this._counter = bytes;
-        };
-        Counter.prototype.increment = function() {
-          for (var i2 = 15; i2 >= 0; i2--) {
-            if (this._counter[i2] === 255) {
-              this._counter[i2] = 0;
-            } else {
-              this._counter[i2]++;
-              break;
+          this._counter = bytes;
+        };
+        Counter.prototype.increment = function() {
+          for (var i3 = 15; i3 >= 0; i3--) {
+            if (this._counter[i3] === 255) {
+              this._counter[i3] = 0;
+            } else {
+              this._counter[i3]++;
+              break;
             }
           }
         };
         };
         ModeOfOperationCTR.prototype.encrypt = function(plaintext) {
           var encrypted = coerceArray(plaintext, true);
-          for (var i2 = 0; i2 < encrypted.length; i2++) {
+          for (var i3 = 0; i3 < encrypted.length; i3++) {
             if (this._remainingCounterIndex === 16) {
               this._remainingCounter = this._aes.encrypt(this._counter._counter);
               this._remainingCounterIndex = 0;
               this._counter.increment();
             }
-            encrypted[i2] ^= this._remainingCounter[this._remainingCounterIndex++];
+            encrypted[i3] ^= this._remainingCounter[this._remainingCounterIndex++];
           }
           return encrypted;
         };
           var padder = 16 - data.length % 16;
           var result = createArray(data.length + padder);
           copyArray(data, result);
-          for (var i2 = data.length; i2 < result.length; i2++) {
-            result[i2] = padder;
+          for (var i3 = data.length; i3 < result.length; i3++) {
+            result[i3] = padder;
           }
           return result;
         }
           if (padder > 16) {
             throw new Error("PKCS#7 padding byte out of range");
           }
-          var length = data.length - padder;
-          for (var i2 = 0; i2 < padder; i2++) {
-            if (data[length + i2] !== padder) {
+          var length2 = data.length - padder;
+          for (var i3 = 0; i3 < padder; i3++) {
+            if (data[length2 + i3] !== padder) {
               throw new Error("PKCS#7 invalid padding byte");
             }
           }
-          var result = createArray(length);
-          copyArray(data, result, 0, 0, length);
+          var result = createArray(length2);
+          copyArray(data, result, 0, 0, length2);
           return result;
         }
         var aesjs2 = {
     }
   });
 
-  // 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_INTEGER4 = 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]", numberTag4 = "[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[numberTag4] = 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[numberTag4] = 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");
-          } catch (e) {
+            return freeProcess2 && freeProcess2.binding && freeProcess2.binding("util");
+          } catch (e3) {
           }
         }();
-        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 func.apply(thisArg, args);
         }
         function arrayAggregator(array2, setter, iteratee, accumulator) {
-          var index = -1, length = array2 == null ? 0 : array2.length;
-          while (++index < length) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length;
+          while (++index < length2) {
             var value = array2[index];
             setter(accumulator, value, iteratee(value), array2);
           }
           return accumulator;
         }
         function arrayEach(array2, iteratee) {
-          var index = -1, length = array2 == null ? 0 : array2.length;
-          while (++index < length) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length;
+          while (++index < length2) {
             if (iteratee(array2[index], index, array2) === false) {
               break;
             }
           return array2;
         }
         function arrayEachRight(array2, iteratee) {
-          var length = array2 == null ? 0 : array2.length;
-          while (length--) {
-            if (iteratee(array2[length], length, array2) === false) {
+          var length2 = array2 == null ? 0 : array2.length;
+          while (length2--) {
+            if (iteratee(array2[length2], length2, array2) === false) {
               break;
             }
           }
           return array2;
         }
         function arrayEvery(array2, predicate) {
-          var index = -1, length = array2 == null ? 0 : array2.length;
-          while (++index < length) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length;
+          while (++index < length2) {
             if (!predicate(array2[index], index, array2)) {
               return false;
             }
           }
           return true;
         }
-        function arrayFilter(array2, predicate) {
-          var index = -1, length = array2 == null ? 0 : array2.length, resIndex = 0, result = [];
-          while (++index < length) {
+        function arrayFilter2(array2, predicate) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length, resIndex = 0, result = [];
+          while (++index < length2) {
             var value = array2[index];
             if (predicate(value, index, array2)) {
               result[resIndex++] = value;
           return result;
         }
         function arrayIncludes(array2, value) {
-          var length = array2 == null ? 0 : array2.length;
-          return !!length && baseIndexOf(array2, value, 0) > -1;
+          var length2 = array2 == null ? 0 : array2.length;
+          return !!length2 && baseIndexOf(array2, value, 0) > -1;
         }
         function arrayIncludesWith(array2, value, comparator) {
-          var index = -1, length = array2 == null ? 0 : array2.length;
-          while (++index < length) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length;
+          while (++index < length2) {
             if (comparator(value, array2[index])) {
               return true;
             }
           return false;
         }
         function arrayMap2(array2, iteratee) {
-          var index = -1, length = array2 == null ? 0 : array2.length, result = Array(length);
-          while (++index < length) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length, result = Array(length2);
+          while (++index < length2) {
             result[index] = iteratee(array2[index], index, array2);
           }
           return result;
         }
-        function arrayPush(array2, values) {
-          var index = -1, length = values.length, offset = array2.length;
-          while (++index < length) {
+        function arrayPush2(array2, values) {
+          var index = -1, length2 = values.length, offset = array2.length;
+          while (++index < length2) {
             array2[offset + index] = values[index];
           }
           return array2;
         }
         function arrayReduce(array2, iteratee, accumulator, initAccum) {
-          var index = -1, length = array2 == null ? 0 : array2.length;
-          if (initAccum && length) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length;
+          if (initAccum && length2) {
             accumulator = array2[++index];
           }
-          while (++index < length) {
+          while (++index < length2) {
             accumulator = iteratee(accumulator, array2[index], index, array2);
           }
           return accumulator;
         }
         function arrayReduceRight(array2, iteratee, accumulator, initAccum) {
-          var length = array2 == null ? 0 : array2.length;
-          if (initAccum && length) {
-            accumulator = array2[--length];
+          var length2 = array2 == null ? 0 : array2.length;
+          if (initAccum && length2) {
+            accumulator = array2[--length2];
           }
-          while (length--) {
-            accumulator = iteratee(accumulator, array2[length], length, array2);
+          while (length2--) {
+            accumulator = iteratee(accumulator, array2[length2], length2, array2);
           }
           return accumulator;
         }
-        function arraySome(array2, predicate) {
-          var index = -1, length = array2 == null ? 0 : array2.length;
-          while (++index < length) {
+        function arraySome2(array2, predicate) {
+          var index = -1, length2 = array2 == null ? 0 : array2.length;
+          while (++index < length2) {
             if (predicate(array2[index], index, array2)) {
               return true;
             }
           return result;
         }
         function baseFindIndex(array2, predicate, fromIndex, fromRight) {
-          var length = array2.length, index = fromIndex + (fromRight ? 1 : -1);
-          while (fromRight ? index-- : ++index < length) {
+          var length2 = array2.length, index = fromIndex + (fromRight ? 1 : -1);
+          while (fromRight ? index-- : ++index < length2) {
             if (predicate(array2[index], index, array2)) {
               return index;
             }
           return value === value ? strictIndexOf(array2, value, fromIndex) : baseFindIndex(array2, baseIsNaN, fromIndex);
         }
         function baseIndexOfWith(array2, value, fromIndex, comparator) {
-          var index = fromIndex - 1, length = array2.length;
-          while (++index < length) {
+          var index = fromIndex - 1, length2 = array2.length;
+          while (++index < length2) {
             if (comparator(array2[index], value)) {
               return index;
             }
           return value !== value;
         }
         function baseMean(array2, iteratee) {
-          var length = array2 == null ? 0 : array2.length;
-          return length ? baseSum(array2, iteratee) / length : NAN2;
+          var length2 = array2 == null ? 0 : array2.length;
+          return length2 ? baseSum(array2, iteratee) / length2 : NAN2;
         }
         function baseProperty(key) {
           return function(object) {
           return accumulator;
         }
         function baseSortBy(array2, comparer) {
-          var length = array2.length;
+          var length2 = array2.length;
           array2.sort(comparer);
-          while (length--) {
-            array2[length] = array2[length].value;
+          while (length2--) {
+            array2[length2] = array2[length2].value;
           }
           return array2;
         }
         function baseSum(array2, iteratee) {
-          var result, index = -1, length = array2.length;
-          while (++index < length) {
+          var result, index = -1, length2 = array2.length;
+          while (++index < length2) {
             var current = iteratee(array2[index]);
             if (current !== undefined2) {
               result = result === undefined2 ? current : result + current;
           }
           return result;
         }
-        function baseTimes(n2, iteratee) {
-          var index = -1, result = Array(n2);
-          while (++index < n2) {
+        function baseTimes2(n3, iteratee) {
+          var index = -1, result = Array(n3);
+          while (++index < n3) {
             result[index] = iteratee(index);
           }
           return result;
         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) {
-          var index = -1, length = strSymbols.length;
-          while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {
+          var index = -1, length2 = strSymbols.length;
+          while (++index < length2 && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {
           }
           return index;
         }
           return index;
         }
         function countHolders(array2, placeholder) {
-          var length = array2.length, result = 0;
-          while (length--) {
-            if (array2[length] === placeholder) {
+          var length2 = array2.length, result = 0;
+          while (length2--) {
+            if (array2[length2] === placeholder) {
               ++result;
             }
           }
         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));
           };
         }
         function replaceHolders(array2, placeholder) {
-          var index = -1, length = array2.length, resIndex = 0, result = [];
-          while (++index < length) {
+          var index = -1, length2 = array2.length, resIndex = 0, result = [];
+          while (++index < length2) {
             var value = array2[index];
             if (value === placeholder || value === PLACEHOLDER) {
               array2[index] = PLACEHOLDER;
           }
           return result;
         }
-        function setToArray(set3) {
-          var index = -1, result = Array(set3.size);
-          set3.forEach(function(value) {
+        function setToArray2(set4) {
+          var index = -1, result = Array(set4.size);
+          set4.forEach(function(value) {
             result[++index] = value;
           });
           return result;
         }
-        function setToPairs(set3) {
-          var index = -1, result = Array(set3.size);
-          set3.forEach(function(value) {
+        function setToPairs(set4) {
+          var index = -1, result = Array(set4.size);
+          set4.forEach(function(value) {
             result[++index] = [value, value];
           });
           return result;
         }
         function strictIndexOf(array2, value, fromIndex) {
-          var index = fromIndex - 1, length = array2.length;
-          while (++index < length) {
+          var index = fromIndex - 1, length2 = array2.length;
+          while (++index < length2) {
             if (array2[index] === value) {
               return index;
             }
           return string.match(reUnicodeWord) || [];
         }
         var runInContext = function runInContext2(context) {
-          context = context == null ? root3 : _.defaults(root3.Object(), context, _.pick(root3, contextProps));
+          context = context == null ? root3 : _2.defaults(root3.Object(), context, _2.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) {
+            } catch (e3) {
             }
           }();
           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);
               }
             }
             return new LodashWrapper(value);
           }
-          var baseCreate = function() {
+          var baseCreate = /* @__PURE__ */ function() {
             function object() {
             }
             return function(proto) {
             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
             }
           };
             return result2;
           }
           function lazyValue() {
-            var array2 = this.__wrapped__.value(), dir = this.__dir__, isArr = isArray2(array2), isRight = dir < 0, arrLength = isArr ? array2.length : 0, view = getView(0, arrLength, this.__views__), start2 = view.start, end = view.end, length = end - start2, index = isRight ? end : start2 - 1, iteratees = this.__iteratees__, iterLength = iteratees.length, resIndex = 0, takeCount = nativeMin2(length, this.__takeCount__);
-            if (!isArr || !isRight && arrLength == length && takeCount == length) {
+            var array2 = this.__wrapped__.value(), dir = this.__dir__, isArr = isArray2(array2), isRight = dir < 0, arrLength = isArr ? array2.length : 0, view = getView(0, arrLength, this.__views__), start2 = view.start, end = view.end, length2 = end - start2, index = isRight ? end : start2 - 1, iteratees = this.__iteratees__, iterLength = iteratees.length, resIndex = 0, takeCount = nativeMin2(length2, this.__takeCount__);
+            if (!isArr || !isRight && arrLength == length2 && takeCount == length2) {
               return baseWrapperValue(array2, this.__actions__);
             }
             var result2 = [];
             outer:
-              while (length-- && resIndex < takeCount) {
+              while (length2-- && resIndex < takeCount) {
                 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) {
-            var index = -1, length = entries == null ? 0 : entries.length;
+          function Hash2(entries) {
+            var index = -1, length2 = entries == null ? 0 : entries.length;
             this.clear();
-            while (++index < length) {
+            while (++index < length2) {
               var entry = entries[index];
               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) {
-            var index = -1, length = entries == null ? 0 : entries.length;
+          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, length2 = entries == null ? 0 : entries.length;
             this.clear();
-            while (++index < length) {
+            while (++index < length2) {
               var entry = entries[index];
               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) {
-            var index = -1, length = entries == null ? 0 : entries.length;
+          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, length2 = entries == null ? 0 : entries.length;
             this.clear();
-            while (++index < length) {
+            while (++index < length2) {
               var entry = entries[index];
               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) {
-            var index = -1, length = values2 == null ? 0 : values2.length;
-            this.__data__ = new MapCache();
-            while (++index < length) {
+          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, length2 = values2 == null ? 0 : values2.length;
+            this.__data__ = new MapCache2();
+            while (++index < length2) {
               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) {
-              var pairs = data.__data__;
-              if (!Map2 || pairs.length < LARGE_ARRAY_SIZE - 1) {
-                pairs.push([key, value]);
+            if (data instanceof ListCache2) {
+              var pairs2 = data.__data__;
+              if (!Map3 || pairs2.length < LARGE_ARRAY_SIZE2 - 1) {
+                pairs2.push([key, value]);
                 this.size = ++data.size;
                 return this;
               }
-              data = this.__data__ = new MapCache(pairs);
+              data = this.__data__ = new MapCache2(pairs2);
             }
             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) : [], length2 = 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, length2)))) {
                 result2.push(key);
               }
             }
             return result2;
           }
           function arraySample(array2) {
-            var length = array2.length;
-            return length ? array2[baseRandom(0, length - 1)] : undefined2;
+            var length2 = array2.length;
+            return length2 ? array2[baseRandom(0, length2 - 1)] : undefined2;
           }
-          function arraySampleSize(array2, n2) {
-            return shuffleSelf(copyArray(array2), baseClamp(n2, 0, array2.length));
+          function arraySampleSize(array2, n3) {
+            return shuffleSelf(copyArray(array2), baseClamp(n3, 0, array2.length));
           }
           function arrayShuffle(array2) {
             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) {
-            var length = array2.length;
-            while (length--) {
-              if (eq(array2[length][0], key)) {
-                return length;
+          function assocIndexOf2(array2, key) {
+            var length2 = array2.length;
+            while (length2--) {
+              if (eq2(array2[length2][0], key)) {
+                return length2;
               }
             }
             return -1;
             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);
             }
           }
           function baseAt(object, paths) {
-            var index = -1, length = paths.length, result2 = Array2(length), skip = object == null;
-            while (++index < length) {
+            var index = -1, length2 = paths.length, result2 = Array2(length2), skip = object == null;
+            while (++index < length2) {
               result2[index] = skip ? undefined2 : get4(object, paths[index]);
             }
             return result2;
                 return copyArray(value, result2);
               }
             } else {
-              var tag = getTag(value), isFunc = tag == funcTag || tag == genTag;
-              if (isBuffer(value)) {
+              var tag2 = getTag2(value), isFunc = tag2 == funcTag3 || tag2 == genTag2;
+              if (isBuffer2(value)) {
                 return cloneBuffer(value, isDeep);
               }
-              if (tag == objectTag || tag == argsTag || isFunc && !object) {
+              if (tag2 == objectTag4 || tag2 == argsTag4 || isFunc && !object) {
                 result2 = isFlat || isFunc ? {} : initCloneObject(value);
                 if (!isDeep) {
                   return isFlat ? copySymbolsIn(value, baseAssignIn(result2, value)) : copySymbols(value, baseAssign(result2, value));
                 }
               } else {
-                if (!cloneableTags[tag]) {
+                if (!cloneableTags[tag2]) {
                   return object ? value : {};
                 }
-                result2 = initCloneByTag(value, tag, isDeep);
+                result2 = initCloneByTag(value, tag2, 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);
             };
           }
           function baseConformsTo(object, source, props) {
-            var length = props.length;
+            var length2 = props.length;
             if (object == null) {
-              return !length;
+              return !length2;
             }
             object = Object2(object);
-            while (length--) {
-              var key = props[length], predicate = source[key], value = object[key];
+            while (length2--) {
+              var key = props[length2], predicate = source[key], value = object[key];
               if (value === undefined2 && !(key in object) || !predicate(value)) {
                 return false;
               }
             }, wait);
           }
           function baseDifference(array2, values2, iteratee2, comparator) {
-            var index = -1, includes2 = arrayIncludes, isCommon = true, length = array2.length, result2 = [], valuesLength = values2.length;
-            if (!length) {
+            var index = -1, includes2 = arrayIncludes, isCommon = true, length2 = array2.length, result2 = [], valuesLength = values2.length;
+            if (!length2) {
               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) {
+              while (++index < length2) {
                 var value = array2[index], computed = iteratee2 == null ? value : iteratee2(value);
                 value = comparator || value !== 0 ? value : 0;
                 if (isCommon && computed === computed) {
             return result2;
           }
           function baseExtremum(array2, iteratee2, comparator) {
-            var index = -1, length = array2.length;
-            while (++index < length) {
+            var index = -1, length2 = array2.length;
+            while (++index < length2) {
               var value = array2[index], current = iteratee2(value);
               if (current != null && (computed === undefined2 ? current === current && !isSymbol2(current) : comparator(current, computed))) {
                 var computed = current, result2 = value;
             return result2;
           }
           function baseFill(array2, value, start2, end) {
-            var length = array2.length;
+            var length2 = array2.length;
             start2 = toInteger(start2);
             if (start2 < 0) {
-              start2 = -start2 > length ? 0 : length + start2;
+              start2 = -start2 > length2 ? 0 : length2 + start2;
             }
-            end = end === undefined2 || end > length ? length : toInteger(end);
+            end = end === undefined2 || end > length2 ? length2 : toInteger(end);
             if (end < 0) {
-              end += length;
+              end += length2;
             }
             end = start2 > end ? 0 : toLength(end);
             while (start2 < end) {
             return result2;
           }
           function baseFlatten(array2, depth, predicate, isStrict, result2) {
-            var index = -1, length = array2.length;
+            var index = -1, length2 = array2.length;
             predicate || (predicate = isFlattenable);
             result2 || (result2 = []);
-            while (++index < length) {
+            while (++index < length2) {
               var value = array2[index];
               if (depth > 0 && predicate(value)) {
                 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) {
             path = castPath(path, object);
-            var index = 0, length = path.length;
-            while (object != null && index < length) {
+            var index = 0, length2 = path.length;
+            while (object != null && index < length2) {
               object = object[toKey(path[index++])];
             }
-            return index && index == length ? object : undefined2;
+            return index && index == length2 ? 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);
             return number3 >= nativeMin2(start2, end) && number3 < nativeMax2(start2, end);
           }
           function baseIntersection(arrays, iteratee2, comparator) {
-            var includes2 = comparator ? arrayIncludesWith : arrayIncludes, length = arrays[0].length, othLength = arrays.length, othIndex = othLength, caches = Array2(othLength), maxLength = Infinity, result2 = [];
+            var includes2 = comparator ? arrayIncludesWith : arrayIncludes, length2 = arrays[0].length, othLength = arrays.length, othIndex = othLength, caches = Array2(othLength), maxLength = Infinity, result2 = [];
             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 || length2 >= 120 && array2.length >= 120) ? new SetCache2(othIndex && array2) : undefined2;
             }
             array2 = arrays[0];
             var index = -1, seen = caches[0];
             outer:
-              while (++index < length && result2.length < maxLength) {
+              while (++index < length2 && 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;
+            var index = matchData.length, length2 = index, noCustomizer = !customizer;
             if (object == null) {
-              return !length;
+              return !length2;
             }
             object = Object2(object);
             while (index--) {
                 return false;
               }
             }
-            while (++index < length) {
+            while (++index < length2) {
               data = matchData[index];
               var key = data[0], objValue = object[key], srcValue = data[1];
               if (noCustomizer && data[2]) {
                   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 (!isObject2(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);
               }
             }
             if (!isObject2(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());
+              stack || (stack = new Stack2());
               if (isObject2(srcValue)) {
                 baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
               } else {
             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 (!isObject2(objValue) || isFunction2(objValue)) {
                   newValue = initCloneObject(srcValue);
                 }
               } else {
             }
             assignMergeValue(object, key, newValue);
           }
-          function baseNth(array2, n2) {
-            var length = array2.length;
-            if (!length) {
+          function baseNth(array2, n3) {
+            var length2 = array2.length;
+            if (!length2) {
               return;
             }
-            n2 += n2 < 0 ? length : 0;
-            return isIndex(n2, length) ? array2[n2] : undefined2;
+            n3 += n3 < 0 ? length2 : 0;
+            return isIndex2(n3, length2) ? array2[n3] : 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);
             });
           }
           function basePickBy(object, paths, predicate) {
-            var index = -1, length = paths.length, result2 = {};
-            while (++index < length) {
+            var index = -1, length2 = paths.length, result2 = {};
+            while (++index < length2) {
               var path = paths[index], value = baseGet(object, path);
               if (predicate(value, path)) {
                 baseSet(result2, castPath(path, object), value);
             };
           }
           function basePullAll(array2, values2, iteratee2, comparator) {
-            var indexOf2 = comparator ? baseIndexOfWith : baseIndexOf, index = -1, length = values2.length, seen = array2;
+            var indexOf2 = comparator ? baseIndexOfWith : baseIndexOf, index = -1, length2 = values2.length, seen = array2;
             if (array2 === values2) {
               values2 = copyArray(values2);
             }
             if (iteratee2) {
-              seen = arrayMap2(array2, baseUnary(iteratee2));
+              seen = arrayMap2(array2, baseUnary2(iteratee2));
             }
-            while (++index < length) {
+            while (++index < length2) {
               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;
           }
           function basePullAt(array2, indexes) {
-            var length = array2 ? indexes.length : 0, lastIndex = length - 1;
-            while (length--) {
-              var index = indexes[length];
-              if (length == lastIndex || index !== previous) {
+            var length2 = array2 ? indexes.length : 0, lastIndex = length2 - 1;
+            while (length2--) {
+              var index = indexes[length2];
+              if (length2 == 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);
                 }
             return lower2 + nativeFloor(nativeRandom() * (upper - lower2 + 1));
           }
           function baseRange(start2, end, step, fromRight) {
-            var index = -1, length = nativeMax2(nativeCeil((end - start2) / (step || 1)), 0), result2 = Array2(length);
-            while (length--) {
-              result2[fromRight ? length : ++index] = start2;
+            var index = -1, length2 = nativeMax2(nativeCeil((end - start2) / (step || 1)), 0), result2 = Array2(length2);
+            while (length2--) {
+              result2[fromRight ? length2 : ++index] = start2;
               start2 += step;
             }
             return result2;
           }
-          function baseRepeat(string, n2) {
+          function baseRepeat(string, n3) {
             var result2 = "";
-            if (!string || n2 < 1 || n2 > MAX_SAFE_INTEGER) {
+            if (!string || n3 < 1 || n3 > MAX_SAFE_INTEGER4) {
               return result2;
             }
             do {
-              if (n2 % 2) {
+              if (n3 % 2) {
                 result2 += string;
               }
-              n2 = nativeFloor(n2 / 2);
-              if (n2) {
+              n3 = nativeFloor(n3 / 2);
+              if (n3) {
                 string += string;
               }
-            } while (n2);
+            } while (n3);
             return result2;
           }
           function baseRest(func, start2) {
           function baseSample(collection) {
             return arraySample(values(collection));
           }
-          function baseSampleSize(collection, n2) {
+          function baseSampleSize(collection, n3) {
             var array2 = values(collection);
-            return shuffleSelf(array2, baseClamp(n2, 0, array2.length));
+            return shuffleSelf(array2, baseClamp(n3, 0, array2.length));
           }
           function baseSet(object, path, value, customizer) {
             if (!isObject2(object)) {
               return object;
             }
             path = castPath(path, object);
-            var index = -1, length = path.length, lastIndex = length - 1, nested = object;
-            while (nested != null && ++index < length) {
+            var index = -1, length2 = path.length, lastIndex = length2 - 1, nested = object;
+            while (nested != null && ++index < length2) {
               var key = toKey(path[index]), newValue = value;
               if (key === "__proto__" || key === "constructor" || key === "prototype") {
                 return object;
                 var objValue = nested[key];
                 newValue = customizer ? customizer(objValue, key, nested) : undefined2;
                 if (newValue === undefined2) {
-                  newValue = isObject2(objValue) ? objValue : isIndex(path[index + 1]) ? [] : {};
+                  newValue = isObject2(objValue) ? objValue : isIndex2(path[index + 1]) ? [] : {};
                 }
               }
               assignValue(nested, key, newValue);
             return shuffleSelf(values(collection));
           }
           function baseSlice(array2, start2, end) {
-            var index = -1, length = array2.length;
+            var index = -1, length2 = array2.length;
             if (start2 < 0) {
-              start2 = -start2 > length ? 0 : length + start2;
+              start2 = -start2 > length2 ? 0 : length2 + start2;
             }
-            end = end > length ? length : end;
+            end = end > length2 ? length2 : end;
             if (end < 0) {
-              end += length;
+              end += length2;
             }
-            length = start2 > end ? 0 : end - start2 >>> 0;
+            length2 = start2 > end ? 0 : end - start2 >>> 0;
             start2 >>>= 0;
-            var result2 = Array2(length);
-            while (++index < length) {
+            var result2 = Array2(length2);
+            while (++index < length2) {
               result2[index] = array2[index + start2];
             }
             return result2;
             return nativeMin2(high, MAX_ARRAY_INDEX);
           }
           function baseSortedUniq(array2, iteratee2) {
-            var index = -1, length = array2.length, resIndex = 0, result2 = [];
-            while (++index < length) {
+            var index = -1, length2 = array2.length, resIndex = 0, result2 = [];
+            while (++index < length2) {
               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;
               }
             return result2 == "0" && 1 / value == -INFINITY2 ? "-0" : result2;
           }
           function baseUniq(array2, iteratee2, comparator) {
-            var index = -1, includes2 = arrayIncludes, length = array2.length, isCommon = true, result2 = [], seen = result2;
+            var index = -1, includes2 = arrayIncludes, length2 = array2.length, isCommon = true, result2 = [], seen = result2;
             if (comparator) {
               isCommon = false;
               includes2 = arrayIncludesWith;
-            } else if (length >= LARGE_ARRAY_SIZE) {
-              var set4 = iteratee2 ? null : createSet(array2);
-              if (set4) {
-                return setToArray(set4);
+            } else if (length2 >= LARGE_ARRAY_SIZE2) {
+              var set5 = iteratee2 ? null : createSet(array2);
+              if (set5) {
+                return setToArray2(set5);
               }
               isCommon = false;
-              includes2 = cacheHas;
-              seen = new SetCache();
+              includes2 = cacheHas2;
+              seen = new SetCache2();
             } else {
               seen = iteratee2 ? [] : result2;
             }
             outer:
-              while (++index < length) {
+              while (++index < length2) {
                 var value = array2[index], computed = iteratee2 ? iteratee2(value) : value;
                 value = comparator || value !== 0 ? value : 0;
                 if (isCommon && computed === computed) {
             return baseSet(object, path, updater(baseGet(object, path)), customizer);
           }
           function baseWhile(array2, predicate, isDrop, fromRight) {
-            var length = array2.length, index = fromRight ? length : -1;
-            while ((fromRight ? index-- : ++index < length) && predicate(array2[index], index, array2)) {
+            var length2 = array2.length, index = fromRight ? length2 : -1;
+            while ((fromRight ? index-- : ++index < length2) && predicate(array2[index], index, array2)) {
             }
-            return isDrop ? baseSlice(array2, fromRight ? 0 : index, fromRight ? index + 1 : length) : baseSlice(array2, fromRight ? index + 1 : 0, fromRight ? length : index);
+            return isDrop ? baseSlice(array2, fromRight ? 0 : index, fromRight ? index + 1 : length2) : baseSlice(array2, fromRight ? index + 1 : 0, fromRight ? length2 : index);
           }
           function baseWrapperValue(value, actions) {
             var result2 = value;
               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) {
-            var length = arrays.length;
-            if (length < 2) {
-              return length ? baseUniq(arrays[0]) : [];
+            var length2 = arrays.length;
+            if (length2 < 2) {
+              return length2 ? baseUniq(arrays[0]) : [];
             }
-            var index = -1, result2 = Array2(length);
-            while (++index < length) {
+            var index = -1, result2 = Array2(length2);
+            while (++index < length2) {
               var array2 = arrays[index], othIndex = -1;
-              while (++othIndex < length) {
+              while (++othIndex < length2) {
                 if (othIndex != index) {
                   result2[index] = baseDifference(result2[index] || array2, arrays[othIndex], iteratee2, comparator);
                 }
             return baseUniq(baseFlatten(result2, 1), iteratee2, comparator);
           }
           function baseZipObject(props, values2, assignFunc) {
-            var index = -1, length = props.length, valsLength = values2.length, result2 = {};
-            while (++index < length) {
+            var index = -1, length2 = props.length, valsLength = values2.length, result2 = {};
+            while (++index < length2) {
               var value = index < valsLength ? values2[index] : undefined2;
               assignFunc(result2, props[index], value);
             }
           }
           var castRest = baseRest;
           function castSlice(array2, start2, end) {
-            var length = array2.length;
-            end = end === undefined2 ? length : end;
-            return !start2 && end >= length ? array2 : baseSlice(array2, start2, end);
+            var length2 = array2.length;
+            end = end === undefined2 ? length2 : end;
+            return !start2 && end >= length2 ? array2 : baseSlice(array2, start2, end);
           }
           var clearTimeout2 = ctxClearTimeout || function(id2) {
             return root3.clearTimeout(id2);
             if (isDeep) {
               return buffer.slice();
             }
-            var length = buffer.length, result2 = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
+            var length2 = buffer.length, result2 = allocUnsafe ? allocUnsafe(length2) : new buffer.constructor(length2);
             buffer.copy(result2);
             return result2;
           }
           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 0;
           }
           function compareMultiple(object, other, orders) {
-            var index = -1, objCriteria = object.criteria, othCriteria = other.criteria, length = objCriteria.length, ordersLength = orders.length;
-            while (++index < length) {
+            var index = -1, objCriteria = object.criteria, othCriteria = other.criteria, length2 = objCriteria.length, ordersLength = orders.length;
+            while (++index < length2) {
               var result2 = compareAscending(objCriteria[index], othCriteria[index]);
               if (result2) {
                 if (index >= ordersLength) {
             return result2;
           }
           function copyArray(source, array2) {
-            var index = -1, length = source.length;
-            array2 || (array2 = Array2(length));
-            while (++index < length) {
+            var index = -1, length2 = source.length;
+            array2 || (array2 = Array2(length2));
+            while (++index < length2) {
               array2[index] = source[index];
             }
             return array2;
           function copyObject(source, props, object, customizer) {
             var isNew = !object;
             object || (object = {});
-            var index = -1, length = props.length;
-            while (++index < length) {
+            var index = -1, length2 = props.length;
+            while (++index < length2) {
               var key = props[index];
               var newValue = customizer ? customizer(object[key], source[key], key, object, source) : undefined2;
               if (newValue === undefined2) {
             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);
           }
           function createAssigner(assigner) {
             return baseRest(function(object, sources) {
-              var index = -1, length = sources.length, customizer = length > 1 ? sources[length - 1] : undefined2, guard = length > 2 ? sources[2] : undefined2;
-              customizer = assigner.length > 3 && typeof customizer == "function" ? (length--, customizer) : undefined2;
+              var index = -1, length2 = sources.length, customizer = length2 > 1 ? sources[length2 - 1] : undefined2, guard = length2 > 2 ? sources[2] : undefined2;
+              customizer = assigner.length > 3 && typeof customizer == "function" ? (length2--, customizer) : undefined2;
               if (guard && isIterateeCall(sources[0], sources[1], guard)) {
-                customizer = length < 3 ? undefined2 : customizer;
-                length = 1;
+                customizer = length2 < 3 ? undefined2 : customizer;
+                length2 = 1;
               }
               object = Object2(object);
-              while (++index < length) {
+              while (++index < length2) {
                 var source = sources[index];
                 if (source) {
                   assigner(object, source, index, customizer);
               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);
-              while (fromRight ? index-- : ++index < length) {
+              var length2 = collection.length, index = fromRight ? length2 : -1, iterable = Object2(collection);
+              while (fromRight ? index-- : ++index < length2) {
                 if (iteratee2(iterable[index], index, iterable) === false) {
                   break;
                 }
           }
           function createBaseFor(fromRight) {
             return function(object, iteratee2, keysFunc) {
-              var index = -1, iterable = Object2(object), props = keysFunc(object), length = props.length;
-              while (length--) {
-                var key = props[fromRight ? length : ++index];
+              var index = -1, iterable = Object2(object), props = keysFunc(object), length2 = props.length;
+              while (length2--) {
+                var key = props[fromRight ? length2 : ++index];
                 if (iteratee2(iterable[key], key, iterable) === false) {
                   break;
                 }
           function createCurry(func, bitmask, arity) {
             var Ctor = createCtor(func);
             function wrapper() {
-              var length = arguments.length, args = Array2(length), index = length, placeholder = getHolder(wrapper);
+              var length2 = arguments.length, args = Array2(length2), index = length2, placeholder = getHolder(wrapper);
               while (index--) {
                 args[index] = arguments[index];
               }
-              var holders = length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder ? [] : replaceHolders(args, placeholder);
-              length -= holders.length;
-              if (length < arity) {
+              var holders = length2 < 3 && args[0] !== placeholder && args[length2 - 1] !== placeholder ? [] : replaceHolders(args, placeholder);
+              length2 -= holders.length;
+              if (length2 < arity) {
                 return createRecurry(
                   func,
                   bitmask,
                   holders,
                   undefined2,
                   undefined2,
-                  arity - length
+                  arity - length2
                 );
               }
               var fn = this && this !== root3 && this instanceof wrapper ? Ctor : func;
           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 createFlow(fromRight) {
             return flatRest(function(funcs) {
-              var length = funcs.length, index = length, prereq = LodashWrapper.prototype.thru;
+              var length2 = funcs.length, index = length2, prereq = LodashWrapper.prototype.thru;
               if (fromRight) {
                 funcs.reverse();
               }
                   var wrapper = new LodashWrapper([], true);
                 }
               }
-              index = wrapper ? index : length;
-              while (++index < length) {
+              index = wrapper ? index : length2;
+              while (++index < length2) {
                 func = funcs[index];
                 var funcName = getFuncName(func), data = funcName == "wrapper" ? getData(func) : undefined2;
                 if (data && isLaziable(data[0]) && data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && !data[4].length && data[9] == 1) {
                 if (wrapper && args.length == 1 && isArray2(value)) {
                   return wrapper.plant(value).value();
                 }
-                var index2 = 0, result2 = length ? funcs[index2].apply(this, args) : value;
-                while (++index2 < length) {
+                var index2 = 0, result2 = length2 ? funcs[index2].apply(this, args) : value;
+                while (++index2 < length2) {
                   result2 = funcs[index2].call(this, result2);
                 }
                 return result2;
           function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary2, arity) {
             var isAry = bitmask & WRAP_ARY_FLAG, isBind = bitmask & WRAP_BIND_FLAG, isBindKey = bitmask & WRAP_BIND_KEY_FLAG, isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), isFlip = bitmask & WRAP_FLIP_FLAG, Ctor = isBindKey ? undefined2 : createCtor(func);
             function wrapper() {
-              var length = arguments.length, args = Array2(length), index = length;
+              var length2 = arguments.length, args = Array2(length2), index = length2;
               while (index--) {
                 args[index] = arguments[index];
               }
               if (partialsRight) {
                 args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
               }
-              length -= holdersCount;
-              if (isCurried && length < arity) {
+              length2 -= holdersCount;
+              if (isCurried && length2 < arity) {
                 var newHolders = replaceHolders(args, placeholder);
                 return createRecurry(
                   func,
                   newHolders,
                   argPos,
                   ary2,
-                  arity - length
+                  arity - length2
                 );
               }
               var thisBinding = isBind ? thisArg : this, fn = isBindKey ? thisBinding[func] : func;
-              length = args.length;
+              length2 = args.length;
               if (argPos) {
                 args = reorder(args, argPos);
-              } else if (isFlip && length > 1) {
+              } else if (isFlip && length2 > 1) {
                 args.reverse();
               }
-              if (isAry && ary2 < length) {
+              if (isAry && ary2 < length2) {
                 args.length = ary2;
               }
               if (this && this !== root3 && this instanceof wrapper) {
           }
           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 createPadding(length, chars) {
+          function createPadding(length2, chars) {
             chars = chars === undefined2 ? " " : baseToString2(chars);
             var charsLength = chars.length;
             if (charsLength < 2) {
-              return charsLength ? baseRepeat(chars, length) : chars;
+              return charsLength ? baseRepeat(chars, length2) : chars;
             }
-            var result2 = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
-            return hasUnicode(chars) ? castSlice(stringToArray(result2), 0, length).join("") : result2.slice(0, length);
+            var result2 = baseRepeat(chars, nativeCeil(length2 / stringSize(chars)));
+            return hasUnicode(chars) ? castSlice(stringToArray(result2), 0, length2).join("") : result2.slice(0, length2);
           }
           function createPartial(func, bitmask, thisArg, partials) {
             var isBind = bitmask & WRAP_BIND_FLAG, Ctor = createCtor(func);
           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);
-              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));
-                pair2 = (toString2(value) + "e").split("e");
-                return +(pair2[0] + "e" + (+pair2[1] - precision2));
+            return function(number3, precision3) {
+              number3 = toNumber3(number3);
+              precision3 = precision3 == null ? 0 : nativeMin2(toInteger(precision3), 292);
+              if (precision3 && nativeIsFinite(number3)) {
+                var pair3 = (toString2(number3) + "e").split("e"), value = func(pair3[0] + "e" + (+pair3[1] + precision3));
+                pair3 = (toString2(value) + "e").split("e");
+                return +(pair3[0] + "e" + (+pair3[1] - precision3));
               }
               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 tag2 = getTag2(object);
+              if (tag2 == mapTag4) {
+                return mapToArray2(object);
               }
-              if (tag == setTag) {
+              if (tag2 == setTag4) {
                 return setToPairs(object);
               }
               return baseToPairs(object, keysFunc(object));
             if (!isBindKey && typeof func != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
-            var length = partials ? partials.length : 0;
-            if (!length) {
+            var length2 = partials ? partials.length : 0;
+            if (!length2) {
               bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
               partials = holders = undefined2;
             }
             ary2 = ary2 === undefined2 ? ary2 : nativeMax2(toInteger(ary2), 0);
             arity = arity === undefined2 ? arity : toInteger(arity);
-            length -= holders ? holders.length : 0;
+            length2 -= holders ? holders.length : 0;
             if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
               var partialsRight = partials, holdersRight = holders;
               partials = holders = undefined2;
             thisArg = newData[2];
             partials = newData[3];
             holders = newData[4];
-            arity = newData[9] = newData[9] === undefined2 ? isBindKey ? 0 : func.length : nativeMax2(newData[9] - length, 0);
+            arity = newData[9] = newData[9] === undefined2 ? isBindKey ? 0 : func.length : nativeMax2(newData[9] - length2, 0);
             if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
               bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
             }
             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 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) {
-            switch (tag) {
-              case dataViewTag:
+          function equalByTag2(object, other, tag2, bitmask, customizer, equalFunc, stack) {
+            switch (tag2) {
+              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 numberTag4:
+                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;
-            while (length--) {
-              var data = array2[length], otherFunc = data.func;
+            var result2 = func.name + "", array2 = realNames[result2], length2 = hasOwnProperty10.call(realNames, result2) ? array2.length : 0;
+            while (length2--) {
+              var data = array2[length2], otherFunc = data.func;
               if (otherFunc == null || otherFunc == func) {
                 return data.name;
               }
             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;
-            while (length--) {
-              var key = result2[length], value = object[key];
-              result2[length] = [key, value, isStrictComparable(value)];
+            var result2 = keys2(object), length2 = result2.length;
+            while (length2--) {
+              var key = result2[length2], value = object[key];
+              result2[length2] = [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), tag2 = value[symToStringTag3];
             try {
               value[symToStringTag3] = undefined2;
               var unmasked = true;
-            } catch (e) {
+            } catch (e3) {
             }
             var result2 = nativeObjectToString3.call(value);
             if (unmasked) {
               if (isOwn) {
-                value[symToStringTag3] = tag;
+                value[symToStringTag3] = tag2;
               } else {
                 delete value[symToStringTag3];
               }
             }
             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;
             };
           }
           function getView(start2, end, transforms) {
-            var index = -1, length = transforms.length;
-            while (++index < length) {
+            var index = -1, length2 = transforms.length;
+            while (++index < length2) {
               var data = transforms[index], size2 = data.size;
               switch (data.type) {
                 case "drop":
           }
           function hasPath(object, path, hasFunc) {
             path = castPath(path, object);
-            var index = -1, length = path.length, result2 = false;
-            while (++index < length) {
+            var index = -1, length2 = path.length, result2 = false;
+            while (++index < length2) {
               var key = toKey(path[index]);
               if (!(result2 = object != null && hasFunc(object, key))) {
                 break;
               }
               object = object[key];
             }
-            if (result2 || ++index != length) {
+            if (result2 || ++index != length2) {
               return result2;
             }
-            length = object == null ? 0 : object.length;
-            return !!length && isLength(length) && isIndex(key, length) && (isArray2(object) || isArguments(object));
+            length2 = object == null ? 0 : object.length;
+            return !!length2 && isLength2(length2) && isIndex2(key, length2) && (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")) {
+            var length2 = array2.length, result2 = new array2.constructor(length2);
+            if (length2 && 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) {
+          function initCloneByTag(object, tag2, isDeep) {
             var Ctor = object.constructor;
-            switch (tag) {
-              case arrayBufferTag:
+            switch (tag2) {
+              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 numberTag4:
+              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);
             }
           }
           function insertWrapDetails(source, details) {
-            var length = details.length;
-            if (!length) {
+            var length2 = details.length;
+            if (!length2) {
               return source;
             }
-            var lastIndex = length - 1;
-            details[lastIndex] = (length > 1 ? "& " : "") + details[lastIndex];
-            details = details.join(length > 2 ? ", " : " ");
+            var lastIndex = length2 - 1;
+            details[lastIndex] = (length2 > 1 ? "& " : "") + details[lastIndex];
+            details = details.join(length2 > 2 ? ", " : " ");
             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, length2) {
+            var type2 = typeof value;
+            length2 = length2 == null ? MAX_SAFE_INTEGER4 : length2;
+            return !!length2 && (type2 == "number" || type2 != "symbol" && reIsUint2.test(value)) && (value > -1 && value % 1 == 0 && value < length2);
           }
           function isIterateeCall(value, index, object) {
             if (!isObject2(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) {
           function overRest(func, start2, transform3) {
             start2 = nativeMax2(start2 === undefined2 ? func.length - 1 : start2, 0);
             return function() {
-              var args = arguments, index = -1, length = nativeMax2(args.length - start2, 0), array2 = Array2(length);
-              while (++index < length) {
+              var args = arguments, index = -1, length2 = nativeMax2(args.length - start2, 0), array2 = Array2(length2);
+              while (++index < length2) {
                 array2[index] = args[start2 + index];
               }
               index = -1;
             return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
           }
           function reorder(array2, indexes) {
-            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;
+            var arrLength = array2.length, length2 = nativeMin2(indexes.length, arrLength), oldArray = copyArray(array2);
+            while (length2--) {
+              var index = indexes[length2];
+              array2[length2] = isIndex2(index, arrLength) ? oldArray[index] : undefined2;
             }
             return array2;
           }
             };
           }
           function shuffleSelf(array2, size2) {
-            var index = -1, length = array2.length, lastIndex = length - 1;
-            size2 = size2 === undefined2 ? length : size2;
+            var index = -1, length2 = array2.length, lastIndex = length2 - 1;
+            size2 = size2 === undefined2 ? length2 : size2;
             while (++index < size2) {
               var rand = baseRandom(index, lastIndex), value = array2[rand];
               array2[rand] = array2[index];
             if (string.charCodeAt(0) === 46) {
               result2.push("");
             }
-            string.replace(rePropName, function(match, number3, quote2, subString) {
-              result2.push(quote2 ? subString.replace(reEscapeChar, "$1") : number3 || match);
+            string.replace(rePropName, function(match, number3, quote, subString) {
+              result2.push(quote ? subString.replace(reEscapeChar, "$1") : number3 || match);
             });
             return result2;
           });
             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);
-              } catch (e) {
+                return funcToString3.call(func);
+              } catch (e3) {
               }
               try {
                 return func + "";
-              } catch (e) {
+              } catch (e3) {
               }
             }
             return "";
           }
           function updateWrapDetails(details, bitmask) {
-            arrayEach(wrapFlags, function(pair2) {
-              var value = "_." + pair2[0];
-              if (bitmask & pair2[1] && !arrayIncludes(details, value)) {
+            arrayEach(wrapFlags, function(pair3) {
+              var value = "_." + pair3[0];
+              if (bitmask & pair3[1] && !arrayIncludes(details, value)) {
                 details.push(value);
               }
             });
             } else {
               size2 = nativeMax2(toInteger(size2), 0);
             }
-            var length = array2 == null ? 0 : array2.length;
-            if (!length || size2 < 1) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2 || size2 < 1) {
               return [];
             }
-            var index = 0, resIndex = 0, result2 = Array2(nativeCeil(length / size2));
-            while (index < length) {
+            var index = 0, resIndex = 0, result2 = Array2(nativeCeil(length2 / size2));
+            while (index < length2) {
               result2[resIndex++] = baseSlice(array2, index, index += size2);
             }
             return result2;
           }
           function compact(array2) {
-            var index = -1, length = array2 == null ? 0 : array2.length, resIndex = 0, result2 = [];
-            while (++index < length) {
+            var index = -1, length2 = array2 == null ? 0 : array2.length, resIndex = 0, result2 = [];
+            while (++index < length2) {
               var value = array2[index];
               if (value) {
                 result2[resIndex++] = value;
             return result2;
           }
           function concat() {
-            var length = arguments.length;
-            if (!length) {
+            var length2 = arguments.length;
+            if (!length2) {
               return [];
             }
-            var args = Array2(length - 1), array2 = arguments[0], index = length;
+            var args = Array2(length2 - 1), array2 = arguments[0], index = length2;
             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) {
+          var difference2 = baseRest(function(array2, values2) {
             return isArrayLikeObject(array2) ? baseDifference(array2, baseFlatten(values2, 1, isArrayLikeObject, true)) : [];
           });
           var differenceBy = baseRest(function(array2, values2) {
             }
             return isArrayLikeObject(array2) ? baseDifference(array2, baseFlatten(values2, 1, isArrayLikeObject, true), undefined2, comparator) : [];
           });
-          function drop(array2, n2, guard) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+          function drop(array2, n3, guard) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return [];
             }
-            n2 = guard || n2 === undefined2 ? 1 : toInteger(n2);
-            return baseSlice(array2, n2 < 0 ? 0 : n2, length);
+            n3 = guard || n3 === undefined2 ? 1 : toInteger(n3);
+            return baseSlice(array2, n3 < 0 ? 0 : n3, length2);
           }
-          function dropRight(array2, n2, guard) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+          function dropRight(array2, n3, guard) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return [];
             }
-            n2 = guard || n2 === undefined2 ? 1 : toInteger(n2);
-            n2 = length - n2;
-            return baseSlice(array2, 0, n2 < 0 ? 0 : n2);
+            n3 = guard || n3 === undefined2 ? 1 : toInteger(n3);
+            n3 = length2 - n3;
+            return baseSlice(array2, 0, n3 < 0 ? 0 : n3);
           }
           function dropRightWhile(array2, predicate) {
             return array2 && array2.length ? baseWhile(array2, getIteratee(predicate, 3), true, true) : [];
             return array2 && array2.length ? baseWhile(array2, getIteratee(predicate, 3), true) : [];
           }
           function fill(array2, value, start2, end) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return [];
             }
             if (start2 && typeof start2 != "number" && isIterateeCall(array2, value, start2)) {
               start2 = 0;
-              end = length;
+              end = length2;
             }
             return baseFill(array2, value, start2, end);
           }
           function findIndex(array2, predicate, fromIndex) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return -1;
             }
             var index = fromIndex == null ? 0 : toInteger(fromIndex);
             if (index < 0) {
-              index = nativeMax2(length + index, 0);
+              index = nativeMax2(length2 + index, 0);
             }
             return baseFindIndex(array2, getIteratee(predicate, 3), index);
           }
           function findLastIndex(array2, predicate, fromIndex) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return -1;
             }
-            var index = length - 1;
+            var index = length2 - 1;
             if (fromIndex !== undefined2) {
               index = toInteger(fromIndex);
-              index = fromIndex < 0 ? nativeMax2(length + index, 0) : nativeMin2(index, length - 1);
+              index = fromIndex < 0 ? nativeMax2(length2 + index, 0) : nativeMin2(index, length2 - 1);
             }
             return baseFindIndex(array2, getIteratee(predicate, 3), index, true);
           }
           function flatten2(array2) {
-            var length = array2 == null ? 0 : array2.length;
-            return length ? baseFlatten(array2, 1) : [];
+            var length2 = array2 == null ? 0 : array2.length;
+            return length2 ? baseFlatten(array2, 1) : [];
           }
           function flattenDeep(array2) {
-            var length = array2 == null ? 0 : array2.length;
-            return length ? baseFlatten(array2, INFINITY2) : [];
+            var length2 = array2 == null ? 0 : array2.length;
+            return length2 ? baseFlatten(array2, INFINITY2) : [];
           }
           function flattenDepth(array2, depth) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return [];
             }
             depth = depth === undefined2 ? 1 : toInteger(depth);
             return baseFlatten(array2, depth);
           }
-          function fromPairs(pairs) {
-            var index = -1, length = pairs == null ? 0 : pairs.length, result2 = {};
-            while (++index < length) {
-              var pair2 = pairs[index];
-              result2[pair2[0]] = pair2[1];
+          function fromPairs(pairs2) {
+            var index = -1, length2 = pairs2 == null ? 0 : pairs2.length, result2 = {};
+            while (++index < length2) {
+              var pair3 = pairs2[index];
+              result2[pair3[0]] = pair3[1];
             }
             return result2;
           }
             return array2 && array2.length ? array2[0] : undefined2;
           }
           function indexOf(array2, value, fromIndex) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return -1;
             }
             var index = fromIndex == null ? 0 : toInteger(fromIndex);
             if (index < 0) {
-              index = nativeMax2(length + index, 0);
+              index = nativeMax2(length2 + index, 0);
             }
             return baseIndexOf(array2, value, index);
           }
           function initial(array2) {
-            var length = array2 == null ? 0 : array2.length;
-            return length ? baseSlice(array2, 0, -1) : [];
+            var length2 = array2 == null ? 0 : array2.length;
+            return length2 ? baseSlice(array2, 0, -1) : [];
           }
-          var intersection = baseRest(function(arrays) {
+          var intersection2 = baseRest(function(arrays) {
             var mapped = arrayMap2(arrays, castArrayLikeObject);
             return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped) : [];
           });
             return array2 == null ? "" : nativeJoin.call(array2, separator);
           }
           function last(array2) {
-            var length = array2 == null ? 0 : array2.length;
-            return length ? array2[length - 1] : undefined2;
+            var length2 = array2 == null ? 0 : array2.length;
+            return length2 ? array2[length2 - 1] : undefined2;
           }
           function lastIndexOf(array2, value, fromIndex) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return -1;
             }
-            var index = length;
+            var index = length2;
             if (fromIndex !== undefined2) {
               index = toInteger(fromIndex);
-              index = index < 0 ? nativeMax2(length + index, 0) : nativeMin2(index, length - 1);
+              index = index < 0 ? nativeMax2(length2 + index, 0) : nativeMin2(index, length2 - 1);
             }
             return value === value ? strictLastIndexOf(array2, value, index) : baseFindIndex(array2, baseIsNaN, index, true);
           }
-          function nth(array2, n2) {
-            return array2 && array2.length ? baseNth(array2, toInteger(n2)) : undefined2;
+          function nth(array2, n3) {
+            return array2 && array2.length ? baseNth(array2, toInteger(n3)) : undefined2;
           }
           var pull = baseRest(pullAll);
           function pullAll(array2, values2) {
             return array2 && array2.length && values2 && values2.length ? basePullAll(array2, values2, undefined2, comparator) : array2;
           }
           var pullAt = flatRest(function(array2, indexes) {
-            var length = array2 == null ? 0 : array2.length, result2 = baseAt(array2, indexes);
+            var length2 = array2 == null ? 0 : array2.length, result2 = baseAt(array2, indexes);
             basePullAt(array2, arrayMap2(indexes, function(index) {
-              return isIndex(index, length) ? +index : index;
+              return isIndex2(index, length2) ? +index : index;
             }).sort(compareAscending));
             return result2;
           });
             if (!(array2 && array2.length)) {
               return result2;
             }
-            var index = -1, indexes = [], length = array2.length;
+            var index = -1, indexes = [], length2 = array2.length;
             predicate = getIteratee(predicate, 3);
-            while (++index < length) {
+            while (++index < length2) {
               var value = array2[index];
               if (predicate(value, index, array2)) {
                 result2.push(value);
             return array2 == null ? array2 : nativeReverse.call(array2);
           }
           function slice(array2, start2, end) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return [];
             }
             if (end && typeof end != "number" && isIterateeCall(array2, start2, end)) {
               start2 = 0;
-              end = length;
+              end = length2;
             } else {
               start2 = start2 == null ? 0 : toInteger(start2);
-              end = end === undefined2 ? length : toInteger(end);
+              end = end === undefined2 ? length2 : toInteger(end);
             }
             return baseSlice(array2, start2, end);
           }
             return baseSortedIndexBy(array2, value, getIteratee(iteratee2, 2));
           }
           function sortedIndexOf(array2, value) {
-            var length = array2 == null ? 0 : array2.length;
-            if (length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (length2) {
               var index = baseSortedIndex(array2, value);
-              if (index < length && eq(array2[index], value)) {
+              if (index < length2 && eq2(array2[index], value)) {
                 return index;
               }
             }
             return baseSortedIndexBy(array2, value, getIteratee(iteratee2, 2), true);
           }
           function sortedLastIndexOf(array2, value) {
-            var length = array2 == null ? 0 : array2.length;
-            if (length) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (length2) {
               var index = baseSortedIndex(array2, value, true) - 1;
-              if (eq(array2[index], value)) {
+              if (eq2(array2[index], value)) {
                 return index;
               }
             }
             return array2 && array2.length ? baseSortedUniq(array2, getIteratee(iteratee2, 2)) : [];
           }
           function tail(array2) {
-            var length = array2 == null ? 0 : array2.length;
-            return length ? baseSlice(array2, 1, length) : [];
+            var length2 = array2 == null ? 0 : array2.length;
+            return length2 ? baseSlice(array2, 1, length2) : [];
           }
-          function take(array2, n2, guard) {
+          function take(array2, n3, guard) {
             if (!(array2 && array2.length)) {
               return [];
             }
-            n2 = guard || n2 === undefined2 ? 1 : toInteger(n2);
-            return baseSlice(array2, 0, n2 < 0 ? 0 : n2);
+            n3 = guard || n3 === undefined2 ? 1 : toInteger(n3);
+            return baseSlice(array2, 0, n3 < 0 ? 0 : n3);
           }
-          function takeRight(array2, n2, guard) {
-            var length = array2 == null ? 0 : array2.length;
-            if (!length) {
+          function takeRight(array2, n3, guard) {
+            var length2 = array2 == null ? 0 : array2.length;
+            if (!length2) {
               return [];
             }
-            n2 = guard || n2 === undefined2 ? 1 : toInteger(n2);
-            n2 = length - n2;
-            return baseSlice(array2, n2 < 0 ? 0 : n2, length);
+            n3 = guard || n3 === undefined2 ? 1 : toInteger(n3);
+            n3 = length2 - n3;
+            return baseSlice(array2, n3 < 0 ? 0 : n3, length2);
           }
           function takeRightWhile(array2, predicate) {
             return array2 && array2.length ? baseWhile(array2, getIteratee(predicate, 3), false, true) : [];
           function takeWhile(array2, predicate) {
             return array2 && array2.length ? baseWhile(array2, getIteratee(predicate, 3)) : [];
           }
-          var union = baseRest(function(arrays) {
+          var union2 = baseRest(function(arrays) {
             return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
           });
           var unionBy = baseRest(function(arrays) {
             if (!(array2 && array2.length)) {
               return [];
             }
-            var length = 0;
-            array2 = arrayFilter(array2, function(group) {
+            var length2 = 0;
+            array2 = arrayFilter2(array2, function(group) {
               if (isArrayLikeObject(group)) {
-                length = nativeMax2(group.length, length);
+                length2 = nativeMax2(group.length, length2);
                 return true;
               }
             });
-            return baseTimes(length, function(index) {
+            return baseTimes2(length2, 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) {
             return baseZipObject(props || [], values2 || [], baseSet);
           }
           var zipWith = baseRest(function(arrays) {
-            var length = arrays.length, iteratee2 = length > 1 ? arrays[length - 1] : undefined2;
+            var length2 = arrays.length, iteratee2 = length2 > 1 ? arrays[length2 - 1] : undefined2;
             iteratee2 = typeof iteratee2 == "function" ? (arrays.pop(), iteratee2) : undefined2;
             return unzipWith(arrays, iteratee2);
           });
             return interceptor(value);
           }
           var wrapperAt = flatRest(function(paths) {
-            var length = paths.length, start2 = length ? paths[0] : 0, value = this.__wrapped__, interceptor = function(object) {
+            var length2 = paths.length, start2 = length2 ? 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 (length2 > 1 || this.__actions__.length || !(value instanceof LazyWrapper) || !isIndex2(start2)) {
               return this.thru(interceptor);
             }
-            value = value.slice(start2, +start2 + (length ? 1 : 0));
+            value = value.slice(start2, +start2 + (length2 ? 1 : 0));
             value.__actions__.push({
               "func": thru,
               "args": [interceptor],
               "thisArg": undefined2
             });
             return new LodashWrapper(value, this.__chain__).thru(function(array2) {
-              if (length && !array2.length) {
+              if (length2 && !array2.length) {
                 array2.push(undefined2);
               }
               return array2;
           function wrapperPlant(value) {
             var result2, parent2 = this;
             while (parent2 instanceof baseLodash) {
-              var clone2 = wrapperClone(parent2);
-              clone2.__index__ = 0;
-              clone2.__values__ = undefined2;
+              var clone3 = wrapperClone(parent2);
+              clone3.__index__ = 0;
+              clone3.__values__ = undefined2;
               if (result2) {
-                previous.__wrapped__ = clone2;
+                previous.__wrapped__ = clone3;
               } else {
-                result2 = clone2;
+                result2 = clone3;
               }
-              var previous = clone2;
+              var previous = clone3;
               parent2 = parent2.__wrapped__;
             }
             previous.__wrapped__ = value;
             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;
+            var length2 = collection.length;
             if (fromIndex < 0) {
-              fromIndex = nativeMax2(length + fromIndex, 0);
+              fromIndex = nativeMax2(length2 + fromIndex, 0);
             }
-            return isString(collection) ? fromIndex <= length && collection.indexOf(value, fromIndex) > -1 : !!length && baseIndexOf(collection, value, fromIndex) > -1;
+            return isString(collection) ? fromIndex <= length2 && collection.indexOf(value, fromIndex) > -1 : !!length2 && 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) {
             var func = isArray2(collection) ? arraySample : baseSample;
             return func(collection);
           }
-          function sampleSize(collection, n2, guard) {
-            if (guard ? isIterateeCall(collection, n2, guard) : n2 === undefined2) {
-              n2 = 1;
+          function sampleSize(collection, n3, guard) {
+            if (guard ? isIterateeCall(collection, n3, guard) : n3 === undefined2) {
+              n3 = 1;
             } else {
-              n2 = toInteger(n2);
+              n3 = toInteger(n3);
             }
             var func = isArray2(collection) ? arraySampleSize : baseSampleSize;
-            return func(collection, n2);
+            return func(collection, n3);
           }
           function shuffle(collection) {
             var func = isArray2(collection) ? arrayShuffle : baseShuffle;
             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 tag2 = getTag2(collection);
+            if (tag2 == mapTag4 || tag2 == 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 (collection == null) {
               return [];
             }
-            var length = iteratees.length;
-            if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
+            var length2 = iteratees.length;
+            if (length2 > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
               iteratees = [];
-            } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
+            } else if (length2 > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
               iteratees = [iteratees[0]];
             }
             return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
           var now3 = ctxNow || function() {
             return root3.Date.now();
           };
-          function after(n2, func) {
+          function after(n3, func) {
             if (typeof func != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
-            n2 = toInteger(n2);
+            n3 = toInteger(n3);
             return function() {
-              if (--n2 < 1) {
+              if (--n3 < 1) {
                 return func.apply(this, arguments);
               }
             };
           }
-          function ary(func, n2, guard) {
-            n2 = guard ? undefined2 : n2;
-            n2 = func && n2 == null ? func.length : n2;
-            return createWrap(func, WRAP_ARY_FLAG, undefined2, undefined2, undefined2, undefined2, n2);
+          function ary(func, n3, guard) {
+            n3 = guard ? undefined2 : n3;
+            n3 = func && n3 == null ? func.length : n3;
+            return createWrap(func, WRAP_ARY_FLAG, undefined2, undefined2, undefined2, undefined2, n3);
           }
-          function before(n2, func) {
+          function before(n3, func) {
             var result2;
             if (typeof func != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
-            n2 = toInteger(n2);
+            n3 = toInteger(n3);
             return function() {
-              if (--n2 > 0) {
+              if (--n3 > 0) {
                 result2 = func.apply(this, arguments);
               }
-              if (n2 <= 1) {
+              if (n3 <= 1) {
                 func = undefined2;
               }
               return result2;
             if (typeof func != "function") {
               throw new TypeError2(FUNC_ERROR_TEXT3);
             }
-            wait = toNumber2(wait) || 0;
+            wait = toNumber3(wait) || 0;
             if (isObject2(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);
-              while (++index < length) {
+              var index = -1, length2 = nativeMin2(args.length, funcsLength);
+              while (++index < length2) {
                 args[index] = transforms[index].call(this, args[index]);
               }
               return apply(func, this, args);
             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);
             });
             var value = arguments[0];
             return isArray2(value) ? value : [value];
           }
-          function clone(value) {
+          function clone2(value) {
             return baseClone(value, CLONE_SYMBOLS_FLAG);
           }
           function cloneWith(value, customizer) {
             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 gt2 = createRelationalOperation(baseGt);
           var gte = createRelationalOperation(function(value, other) {
             return value >= other;
           });
-          var isArguments = baseIsArguments(function() {
+          var isArguments2 = baseIsArguments2(/* @__PURE__ */ 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 tag2 = getTag2(value);
+            if (tag2 == mapTag4 || tag2 == 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);
+            var tag2 = baseGetTag2(value);
+            return tag2 == errorTag3 || tag2 == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject(value);
           }
           function isFinite2(value) {
             return typeof value == "number" && nativeIsFinite(value);
           }
-          function isFunction(value) {
+          function isFunction2(value) {
             if (!isObject2(value)) {
               return false;
             }
-            var tag = baseGetTag2(value);
-            return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
+            var tag2 = baseGetTag2(value);
+            return tag2 == funcTag3 || tag2 == genTag2 || tag2 == asyncTag2 || tag2 == 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_INTEGER4;
           }
           function isObject2(value) {
-            var type3 = typeof value;
-            return value != null && (type3 == "object" || type3 == "function");
+            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) == numberTag4;
           }
           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_INTEGER4 && value <= MAX_SAFE_INTEGER4;
           }
-          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;
           }
-          var lt = createRelationalOperation(baseLt);
+          var lt2 = createRelationalOperation(baseLt);
           var lte = createRelationalOperation(function(value, other) {
             return value <= other;
           });
             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 tag2 = getTag2(value), func = tag2 == mapTag4 ? mapToArray2 : tag2 == 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;
             }
             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_INTEGER4, MAX_SAFE_INTEGER4) : 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);
+          var at2 = flatRest(baseAt);
           function create2(prototype, properties) {
             var result2 = baseCreate(prototype);
             return properties == null ? result2 : baseAssign(result2, properties);
           }
-          var defaults2 = baseRest(function(object, sources) {
+          var defaults = baseRest(function(object, sources) {
             object = Object2(object);
             var index = -1;
-            var length = sources.length;
-            var guard = length > 2 ? sources[2] : undefined2;
+            var length2 = sources.length;
+            var guard = length2 > 2 ? sources[2] : undefined2;
             if (guard && isIterateeCall(sources[0], sources[1], guard)) {
-              length = 1;
+              length2 = 1;
             }
-            while (++index < length) {
+            while (++index < length2) {
               var source = sources[index];
               var props = keysIn(source);
               var propsIndex = -1;
               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) {
             if (isDeep) {
               result2 = baseClone(result2, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
             }
-            var length = paths.length;
-            while (length--) {
-              baseUnset(result2, paths[length]);
+            var length2 = paths.length;
+            while (length2--) {
+              baseUnset(result2, paths[length2]);
             }
             return result2;
           });
           }
           function result(object, path, defaultValue) {
             path = castPath(path, object);
-            var index = -1, length = path.length;
-            if (!length) {
-              length = 1;
+            var index = -1, length2 = path.length;
+            if (!length2) {
+              length2 = 1;
               object = undefined2;
             }
-            while (++index < length) {
+            while (++index < length2) {
               var value = object == null ? undefined2 : object[toKey(path[index])];
               if (value === undefined2) {
-                index = length;
+                index = length2;
                 value = defaultValue;
               }
-              object = isFunction(value) ? value.call(object) : value;
+              object = isFunction2(value) ? value.call(object) : value;
             }
             return object;
           }
-          function set3(object, path, value) {
+          function set4(object, path, value) {
             return object == null ? object : baseSet(object, path, value);
           }
           function setWith(object, path, value, customizer) {
             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)) : {};
+                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 endsWith(string, target, position) {
             string = toString2(string);
             target = baseToString2(target);
-            var length = string.length;
-            position = position === undefined2 ? length : baseClamp(toInteger(position), 0, length);
+            var length2 = string.length;
+            position = position === undefined2 ? length2 : baseClamp(toInteger(position), 0, length2);
             var end = position;
             position -= target.length;
             return position >= 0 && string.slice(position, end) == target;
           }
           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();
             return result2 + (index ? " " : "") + word.toLowerCase();
           });
           var lowerFirst = createCaseFirst("toLowerCase");
-          function pad2(string, length, chars) {
+          function pad2(string, length2, chars) {
             string = toString2(string);
-            length = toInteger(length);
-            var strLength = length ? stringSize(string) : 0;
-            if (!length || strLength >= length) {
+            length2 = toInteger(length2);
+            var strLength = length2 ? stringSize(string) : 0;
+            if (!length2 || strLength >= length2) {
               return string;
             }
-            var mid = (length - strLength) / 2;
+            var mid = (length2 - strLength) / 2;
             return createPadding(nativeFloor(mid), chars) + string + createPadding(nativeCeil(mid), chars);
           }
-          function padEnd(string, length, chars) {
+          function padEnd(string, length2, chars) {
             string = toString2(string);
-            length = toInteger(length);
-            var strLength = length ? stringSize(string) : 0;
-            return length && strLength < length ? string + createPadding(length - strLength, chars) : string;
+            length2 = toInteger(length2);
+            var strLength = length2 ? stringSize(string) : 0;
+            return length2 && strLength < length2 ? string + createPadding(length2 - strLength, chars) : string;
           }
-          function padStart(string, length, chars) {
+          function padStart(string, length2, chars) {
             string = toString2(string);
-            length = toInteger(length);
-            var strLength = length ? stringSize(string) : 0;
-            return length && strLength < length ? createPadding(length - strLength, chars) + string : string;
+            length2 = toInteger(length2);
+            var strLength = length2 ? stringSize(string) : 0;
+            return length2 && strLength < length2 ? createPadding(length2 - strLength, chars) + string : string;
           }
           function parseInt2(string, radix, guard) {
             if (guard || radix == null) {
             }
             return nativeParseInt(toString2(string).replace(reTrimStart2, ""), radix || 0);
           }
-          function repeat(string, n2, guard) {
-            if (guard ? isIterateeCall(string, n2, guard) : n2 === undefined2) {
-              n2 = 1;
+          function repeat(string, n3, guard) {
+            if (guard ? isIterateeCall(string, n3, guard) : n3 === undefined2) {
+              n3 = 1;
             } else {
-              n2 = toInteger(n2);
+              n3 = toInteger(n3);
             }
-            return baseRepeat(toString2(string), n2);
+            return baseRepeat(toString2(string), n3);
           }
           function replace() {
             var args = arguments, string = toString2(args[0]);
             }
             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)) {
             return castSlice(strSymbols, start2).join("");
           }
           function truncate(string, options2) {
-            var length = DEFAULT_TRUNC_LENGTH, omission = DEFAULT_TRUNC_OMISSION;
+            var length2 = DEFAULT_TRUNC_LENGTH, omission = DEFAULT_TRUNC_OMISSION;
             if (isObject2(options2)) {
               var separator = "separator" in options2 ? options2.separator : separator;
-              length = "length" in options2 ? toInteger(options2.length) : length;
+              length2 = "length" in options2 ? toInteger(options2.length) : length2;
               omission = "omission" in options2 ? baseToString2(options2.omission) : omission;
             }
             string = toString2(string);
               var strSymbols = stringToArray(string);
               strLength = strSymbols.length;
             }
-            if (length >= strLength) {
+            if (length2 >= strLength) {
               return string;
             }
-            var end = length - stringSize(omission);
+            var end = length2 - stringSize(omission);
             if (end < 1) {
               return omission;
             }
             }
             return result2 + omission;
           }
-          function unescape4(string) {
+          function unescape2(string) {
             string = toString2(string);
             return string && reHasEscapedHtml2.test(string) ? string.replace(reEscapedHtml2, unescapeHtmlChar2) : string;
           }
           var attempt = baseRest(function(func, args) {
             try {
               return apply(func, undefined2, args);
-            } catch (e) {
-              return isError(e) ? e : new Error2(e);
+            } catch (e3) {
+              return isError(e3) ? e3 : new Error2(e3);
             }
           });
           var bindAll = flatRest(function(object, methodNames) {
             });
             return object;
           });
-          function cond(pairs) {
-            var length = pairs == null ? 0 : pairs.length, toIteratee = getIteratee();
-            pairs = !length ? [] : arrayMap2(pairs, function(pair2) {
-              if (typeof pair2[1] != "function") {
+          function cond(pairs2) {
+            var length2 = pairs2 == null ? 0 : pairs2.length, toIteratee = getIteratee();
+            pairs2 = !length2 ? [] : arrayMap2(pairs2, function(pair3) {
+              if (typeof pair3[1] != "function") {
                 throw new TypeError2(FUNC_ERROR_TEXT3);
               }
-              return [toIteratee(pair2[0]), pair2[1]];
+              return [toIteratee(pair3[0]), pair3[1]];
             });
             return baseRest(function(args) {
               var index = -1;
-              while (++index < length) {
-                var pair2 = pairs[index];
-                if (apply(pair2[0], this, args)) {
-                  return apply(pair2[1], this, args);
+              while (++index < length2) {
+                var pair3 = pairs2[index];
+                if (apply(pair3[0], this, args)) {
+                  return apply(pair3[1], this, args);
                 }
               }
             });
             };
           });
           function mixin(object, source, options2) {
-            var props = keys(source), methodNames = baseFunctions(source, props);
+            var props = keys2(source), methodNames = baseFunctions(source, props);
             if (options2 == null && !(isObject2(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 = !(isObject2(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));
                 };
               }
             });
           }
           function noop3() {
           }
-          function nthArg(n2) {
-            n2 = toInteger(n2);
+          function nthArg(n3) {
+            n3 = toInteger(n3);
             return baseRest(function(args) {
-              return baseNth(args, n2);
+              return baseNth(args, n3);
             });
           }
           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 stubTrue() {
             return true;
           }
-          function times(n2, iteratee2) {
-            n2 = toInteger(n2);
-            if (n2 < 1 || n2 > MAX_SAFE_INTEGER) {
+          function times(n3, iteratee2) {
+            n3 = toInteger(n3);
+            if (n3 < 1 || n3 > MAX_SAFE_INTEGER4) {
               return [];
             }
-            var index = MAX_ARRAY_LENGTH, length = nativeMin2(n2, MAX_ARRAY_LENGTH);
+            var index = MAX_ARRAY_LENGTH, length2 = nativeMin2(n3, MAX_ARRAY_LENGTH);
             iteratee2 = getIteratee(iteratee2);
-            n2 -= MAX_ARRAY_LENGTH;
-            var result2 = baseTimes(length, iteratee2);
-            while (++index < n2) {
+            n3 -= MAX_ARRAY_LENGTH;
+            var result2 = baseTimes2(length2, iteratee2);
+            while (++index < n3) {
               iteratee2(index);
             }
             return result2;
           lodash.assignIn = assignIn;
           lodash.assignInWith = assignInWith;
           lodash.assignWith = assignWith;
-          lodash.at = at;
+          lodash.at = at2;
           lodash.before = before;
           lodash.bind = bind;
           lodash.bindAll = bindAll;
           lodash.curry = curry;
           lodash.curryRight = curryRight;
           lodash.debounce = debounce2;
-          lodash.defaults = defaults2;
+          lodash.defaults = defaults;
           lodash.defaultsDeep = defaultsDeep;
           lodash.defer = defer;
           lodash.delay = delay;
-          lodash.difference = difference;
+          lodash.difference = difference2;
           lodash.differenceBy = differenceBy;
           lodash.differenceWith = differenceWith;
           lodash.drop = drop;
           lodash.functionsIn = functionsIn;
           lodash.groupBy = groupBy;
           lodash.initial = initial;
-          lodash.intersection = intersection;
+          lodash.intersection = intersection2;
           lodash.intersectionBy = intersectionBy;
           lodash.intersectionWith = intersectionWith;
           lodash.invert = invert;
           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.rest = rest;
           lodash.reverse = reverse;
           lodash.sampleSize = sampleSize;
-          lodash.set = set3;
+          lodash.set = set4;
           lodash.setWith = setWith;
           lodash.shuffle = shuffle;
           lodash.slice = slice;
           lodash.toPlainObject = toPlainObject;
           lodash.transform = transform2;
           lodash.unary = unary;
-          lodash.union = union;
+          lodash.union = union2;
           lodash.unionBy = unionBy;
           lodash.unionWith = unionWith;
           lodash.uniq = uniq;
           lodash.capitalize = capitalize;
           lodash.ceil = ceil;
           lodash.clamp = clamp3;
-          lodash.clone = clone;
+          lodash.clone = clone2;
           lodash.cloneDeep = cloneDeep;
           lodash.cloneDeepWith = cloneDeepWith;
           lodash.cloneWith = cloneWith;
           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.forOwn = forOwn;
           lodash.forOwnRight = forOwnRight;
           lodash.get = get4;
-          lodash.gt = gt;
+          lodash.gt = gt2;
           lodash.gte = gte;
           lodash.has = has;
           lodash.hasIn = hasIn;
           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.isSet = isSet;
           lodash.isString = isString;
           lodash.isSymbol = isSymbol2;
-          lodash.isTypedArray = isTypedArray;
+          lodash.isTypedArray = isTypedArray2;
           lodash.isUndefined = isUndefined;
           lodash.isWeakMap = isWeakMap;
           lodash.isWeakSet = isWeakSet;
           lodash.lastIndexOf = lastIndexOf;
           lodash.lowerCase = lowerCase;
           lodash.lowerFirst = lowerFirst;
-          lodash.lt = lt;
+          lodash.lt = lt2;
           lodash.lte = lte;
           lodash.max = max3;
           lodash.maxBy = maxBy;
           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;
           lodash.trimEnd = trimEnd;
           lodash.trimStart = trimStart;
           lodash.truncate = truncate;
-          lodash.unescape = unescape4;
+          lodash.unescape = unescape2;
           lodash.uniqueId = uniqueId;
           lodash.upperCase = upperCase;
           lodash.upperFirst = upperFirst;
           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;
               }
             });
             lodash[methodName].placeholder = lodash;
           });
           arrayEach(["drop", "take"], function(methodName, index) {
-            LazyWrapper.prototype[methodName] = function(n2) {
-              n2 = n2 === undefined2 ? 1 : nativeMax2(toInteger(n2), 0);
+            LazyWrapper.prototype[methodName] = function(n3) {
+              n3 = n3 === undefined2 ? 1 : nativeMax2(toInteger(n3), 0);
               var result2 = this.__filtered__ && !index ? new LazyWrapper(this) : this.clone();
               if (result2.__filtered__) {
-                result2.__takeCount__ = nativeMin2(n2, result2.__takeCount__);
+                result2.__takeCount__ = nativeMin2(n3, result2.__takeCount__);
               } else {
                 result2.__views__.push({
-                  "size": nativeMin2(n2, MAX_ARRAY_LENGTH),
+                  "size": nativeMin2(n3, MAX_ARRAY_LENGTH),
                   "type": methodName + (result2.__dir__ < 0 ? "Right" : "")
                 });
               }
               return result2;
             };
-            LazyWrapper.prototype[methodName + "Right"] = function(n2) {
-              return this.reverse()[methodName](n2).reverse();
+            LazyWrapper.prototype[methodName + "Right"] = function(n3) {
+              return this.reverse()[methodName](n3).reverse();
             };
           });
           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 });
           }
           return lodash;
         };
-        var _ = runInContext();
+        var _2 = runInContext();
         if (typeof define == "function" && typeof define.amd == "object" && define.amd) {
-          root3._ = _;
+          root3._ = _2;
           define(function() {
-            return _;
+            return _2;
           });
-        } else if (freeModule) {
-          (freeModule.exports = _)._ = _;
-          freeExports._ = _;
+        } else if (freeModule3) {
+          (freeModule3.exports = _2)._ = _2;
+          freeExports3._ = _2;
         } else {
-          root3._ = _;
+          root3._ = _2;
         }
       }).call(exports2);
     }
   });
 
-  // node_modules/rbush/rbush.min.js
-  var require_rbush_min = __commonJS({
-    "node_modules/rbush/rbush.min.js"(exports2, module2) {
-      !function(t, i2) {
-        "object" == typeof exports2 && "undefined" != typeof module2 ? module2.exports = i2() : "function" == typeof define && define.amd ? define(i2) : (t = t || self).RBush = i2();
-      }(exports2, function() {
-        "use strict";
-        function t(t2, r2, e3, a2, h2) {
-          !function t3(n3, r3, e4, a3, h3) {
-            for (; a3 > e4; ) {
-              if (a3 - e4 > 600) {
-                var o2 = a3 - e4 + 1, s2 = r3 - e4 + 1, l2 = Math.log(o2), f3 = 0.5 * Math.exp(2 * l2 / 3), u2 = 0.5 * Math.sqrt(l2 * f3 * (o2 - f3) / o2) * (s2 - o2 / 2 < 0 ? -1 : 1), m2 = Math.max(e4, Math.floor(r3 - s2 * f3 / o2 + u2)), c2 = Math.min(a3, Math.floor(r3 + (o2 - s2) * f3 / o2 + u2));
-                t3(n3, r3, m2, c2, h3);
-              }
-              var p2 = n3[r3], d2 = e4, x = a3;
-              for (i2(n3, e4, r3), h3(n3[a3], p2) > 0 && i2(n3, e4, a3); d2 < x; ) {
-                for (i2(n3, d2, x), d2++, x--; h3(n3[d2], p2) < 0; )
-                  d2++;
-                for (; h3(n3[x], p2) > 0; )
-                  x--;
-              }
-              0 === h3(n3[e4], p2) ? i2(n3, e4, x) : i2(n3, ++x, a3), x <= r3 && (e4 = x + 1), r3 <= x && (a3 = x - 1);
-            }
-          }(t2, r2, e3 || 0, a2 || t2.length - 1, h2 || n2);
-        }
-        function i2(t2, i3, n3) {
-          var r2 = t2[i3];
-          t2[i3] = t2[n3], t2[n3] = r2;
-        }
-        function n2(t2, i3) {
-          return t2 < i3 ? -1 : t2 > i3 ? 1 : 0;
-        }
-        var r = function(t2) {
-          void 0 === t2 && (t2 = 9), this._maxEntries = Math.max(4, t2), this._minEntries = Math.max(2, Math.ceil(0.4 * this._maxEntries)), this.clear();
-        };
-        function e(t2, i3, n3) {
-          if (!n3)
-            return i3.indexOf(t2);
-          for (var r2 = 0; r2 < i3.length; r2++)
-            if (n3(t2, i3[r2]))
-              return r2;
-          return -1;
-        }
-        function a(t2, i3) {
-          h(t2, 0, t2.children.length, i3, t2);
-        }
-        function h(t2, i3, n3, r2, e3) {
-          e3 || (e3 = p(null)), e3.minX = 1 / 0, e3.minY = 1 / 0, e3.maxX = -1 / 0, e3.maxY = -1 / 0;
-          for (var a2 = i3; a2 < n3; a2++) {
-            var h2 = t2.children[a2];
-            o(e3, t2.leaf ? r2(h2) : h2);
-          }
-          return e3;
-        }
-        function o(t2, i3) {
-          return t2.minX = Math.min(t2.minX, i3.minX), t2.minY = Math.min(t2.minY, i3.minY), t2.maxX = Math.max(t2.maxX, i3.maxX), t2.maxY = Math.max(t2.maxY, i3.maxY), t2;
-        }
-        function s(t2, i3) {
-          return t2.minX - i3.minX;
-        }
-        function l(t2, i3) {
-          return t2.minY - i3.minY;
-        }
-        function f2(t2) {
-          return (t2.maxX - t2.minX) * (t2.maxY - t2.minY);
-        }
-        function u(t2) {
-          return t2.maxX - t2.minX + (t2.maxY - t2.minY);
-        }
-        function m(t2, i3) {
-          return t2.minX <= i3.minX && t2.minY <= i3.minY && i3.maxX <= t2.maxX && i3.maxY <= t2.maxY;
-        }
-        function c(t2, i3) {
-          return i3.minX <= t2.maxX && i3.minY <= t2.maxY && i3.maxX >= t2.minX && i3.maxY >= t2.minY;
-        }
-        function p(t2) {
-          return { children: t2, height: 1, leaf: true, minX: 1 / 0, minY: 1 / 0, maxX: -1 / 0, maxY: -1 / 0 };
-        }
-        function d(i3, n3, r2, e3, a2) {
-          for (var h2 = [n3, r2]; h2.length; )
-            if (!((r2 = h2.pop()) - (n3 = h2.pop()) <= e3)) {
-              var o2 = n3 + Math.ceil((r2 - n3) / e3 / 2) * e3;
-              t(i3, o2, n3, r2, a2), h2.push(n3, o2, o2, r2);
-            }
-        }
-        return r.prototype.all = function() {
-          return this._all(this.data, []);
-        }, r.prototype.search = function(t2) {
-          var i3 = this.data, n3 = [];
-          if (!c(t2, i3))
-            return n3;
-          for (var r2 = this.toBBox, e3 = []; i3; ) {
-            for (var a2 = 0; a2 < i3.children.length; a2++) {
-              var h2 = i3.children[a2], o2 = i3.leaf ? r2(h2) : h2;
-              c(t2, o2) && (i3.leaf ? n3.push(h2) : m(t2, o2) ? this._all(h2, n3) : e3.push(h2));
-            }
-            i3 = e3.pop();
-          }
-          return n3;
-        }, r.prototype.collides = function(t2) {
-          var i3 = this.data;
-          if (!c(t2, i3))
-            return false;
-          for (var n3 = []; i3; ) {
-            for (var r2 = 0; r2 < i3.children.length; r2++) {
-              var e3 = i3.children[r2], a2 = i3.leaf ? this.toBBox(e3) : e3;
-              if (c(t2, a2)) {
-                if (i3.leaf || m(t2, a2))
-                  return true;
-                n3.push(e3);
-              }
-            }
-            i3 = n3.pop();
-          }
-          return false;
-        }, r.prototype.load = function(t2) {
-          if (!t2 || !t2.length)
-            return this;
-          if (t2.length < this._minEntries) {
-            for (var i3 = 0; i3 < t2.length; i3++)
-              this.insert(t2[i3]);
-            return this;
-          }
-          var n3 = this._build(t2.slice(), 0, t2.length - 1, 0);
-          if (this.data.children.length)
-            if (this.data.height === n3.height)
-              this._splitRoot(this.data, n3);
-            else {
-              if (this.data.height < n3.height) {
-                var r2 = this.data;
-                this.data = n3, n3 = r2;
-              }
-              this._insert(n3, this.data.height - n3.height - 1, true);
-            }
-          else
-            this.data = n3;
-          return this;
-        }, r.prototype.insert = function(t2) {
-          return t2 && this._insert(t2, this.data.height - 1), this;
-        }, r.prototype.clear = function() {
-          return this.data = p([]), this;
-        }, r.prototype.remove = function(t2, i3) {
-          if (!t2)
-            return this;
-          for (var n3, r2, a2, h2 = this.data, o2 = this.toBBox(t2), s2 = [], l2 = []; h2 || s2.length; ) {
-            if (h2 || (h2 = s2.pop(), r2 = s2[s2.length - 1], n3 = l2.pop(), a2 = true), h2.leaf) {
-              var f3 = e(t2, h2.children, i3);
-              if (-1 !== f3)
-                return h2.children.splice(f3, 1), s2.push(h2), this._condense(s2), this;
-            }
-            a2 || h2.leaf || !m(h2, o2) ? r2 ? (n3++, h2 = r2.children[n3], a2 = false) : h2 = null : (s2.push(h2), l2.push(n3), n3 = 0, r2 = h2, h2 = h2.children[0]);
-          }
-          return this;
-        }, r.prototype.toBBox = function(t2) {
-          return t2;
-        }, r.prototype.compareMinX = function(t2, i3) {
-          return t2.minX - i3.minX;
-        }, r.prototype.compareMinY = function(t2, i3) {
-          return t2.minY - i3.minY;
-        }, r.prototype.toJSON = function() {
-          return this.data;
-        }, r.prototype.fromJSON = function(t2) {
-          return this.data = t2, this;
-        }, r.prototype._all = function(t2, i3) {
-          for (var n3 = []; t2; )
-            t2.leaf ? i3.push.apply(i3, t2.children) : n3.push.apply(n3, t2.children), t2 = n3.pop();
-          return i3;
-        }, r.prototype._build = function(t2, i3, n3, r2) {
-          var e3, h2 = n3 - i3 + 1, o2 = this._maxEntries;
-          if (h2 <= o2)
-            return a(e3 = p(t2.slice(i3, n3 + 1)), this.toBBox), e3;
-          r2 || (r2 = Math.ceil(Math.log(h2) / Math.log(o2)), o2 = Math.ceil(h2 / Math.pow(o2, r2 - 1))), (e3 = p([])).leaf = false, e3.height = r2;
-          var s2 = Math.ceil(h2 / o2), l2 = s2 * Math.ceil(Math.sqrt(o2));
-          d(t2, i3, n3, l2, this.compareMinX);
-          for (var f3 = i3; f3 <= n3; f3 += l2) {
-            var u2 = Math.min(f3 + l2 - 1, n3);
-            d(t2, f3, u2, s2, this.compareMinY);
-            for (var m2 = f3; m2 <= u2; m2 += s2) {
-              var c2 = Math.min(m2 + s2 - 1, u2);
-              e3.children.push(this._build(t2, m2, c2, r2 - 1));
-            }
-          }
-          return a(e3, this.toBBox), e3;
-        }, r.prototype._chooseSubtree = function(t2, i3, n3, r2) {
-          for (; r2.push(i3), !i3.leaf && r2.length - 1 !== n3; ) {
-            for (var e3 = 1 / 0, a2 = 1 / 0, h2 = void 0, o2 = 0; o2 < i3.children.length; o2++) {
-              var s2 = i3.children[o2], l2 = f2(s2), u2 = (m2 = t2, c2 = s2, (Math.max(c2.maxX, m2.maxX) - Math.min(c2.minX, m2.minX)) * (Math.max(c2.maxY, m2.maxY) - Math.min(c2.minY, m2.minY)) - l2);
-              u2 < a2 ? (a2 = u2, e3 = l2 < e3 ? l2 : e3, h2 = s2) : u2 === a2 && l2 < e3 && (e3 = l2, h2 = s2);
-            }
-            i3 = h2 || i3.children[0];
-          }
-          var m2, c2;
-          return i3;
-        }, r.prototype._insert = function(t2, i3, n3) {
-          var r2 = n3 ? t2 : this.toBBox(t2), e3 = [], a2 = this._chooseSubtree(r2, this.data, i3, e3);
-          for (a2.children.push(t2), o(a2, r2); i3 >= 0 && e3[i3].children.length > this._maxEntries; )
-            this._split(e3, i3), i3--;
-          this._adjustParentBBoxes(r2, e3, i3);
-        }, r.prototype._split = function(t2, i3) {
-          var n3 = t2[i3], r2 = n3.children.length, e3 = this._minEntries;
-          this._chooseSplitAxis(n3, e3, r2);
-          var h2 = this._chooseSplitIndex(n3, e3, r2), o2 = p(n3.children.splice(h2, n3.children.length - h2));
-          o2.height = n3.height, o2.leaf = n3.leaf, a(n3, this.toBBox), a(o2, this.toBBox), i3 ? t2[i3 - 1].children.push(o2) : this._splitRoot(n3, o2);
-        }, r.prototype._splitRoot = function(t2, i3) {
-          this.data = p([t2, i3]), this.data.height = t2.height + 1, this.data.leaf = false, a(this.data, this.toBBox);
-        }, r.prototype._chooseSplitIndex = function(t2, i3, n3) {
-          for (var r2, e3, a2, o2, s2, l2, u2, m2 = 1 / 0, c2 = 1 / 0, p2 = i3; p2 <= n3 - i3; p2++) {
-            var d2 = h(t2, 0, p2, this.toBBox), x = h(t2, p2, n3, this.toBBox), v = (e3 = d2, a2 = x, o2 = void 0, s2 = void 0, l2 = void 0, u2 = void 0, o2 = Math.max(e3.minX, a2.minX), s2 = Math.max(e3.minY, a2.minY), l2 = Math.min(e3.maxX, a2.maxX), u2 = Math.min(e3.maxY, a2.maxY), Math.max(0, l2 - o2) * Math.max(0, u2 - s2)), M = f2(d2) + f2(x);
-            v < m2 ? (m2 = v, r2 = p2, c2 = M < c2 ? M : c2) : v === m2 && M < c2 && (c2 = M, r2 = p2);
-          }
-          return r2 || n3 - i3;
-        }, r.prototype._chooseSplitAxis = function(t2, i3, n3) {
-          var r2 = t2.leaf ? this.compareMinX : s, e3 = t2.leaf ? this.compareMinY : l;
-          this._allDistMargin(t2, i3, n3, r2) < this._allDistMargin(t2, i3, n3, e3) && t2.children.sort(r2);
-        }, r.prototype._allDistMargin = function(t2, i3, n3, r2) {
-          t2.children.sort(r2);
-          for (var e3 = this.toBBox, a2 = h(t2, 0, i3, e3), s2 = h(t2, n3 - i3, n3, e3), l2 = u(a2) + u(s2), f3 = i3; f3 < n3 - i3; f3++) {
-            var m2 = t2.children[f3];
-            o(a2, t2.leaf ? e3(m2) : m2), l2 += u(a2);
-          }
-          for (var c2 = n3 - i3 - 1; c2 >= i3; c2--) {
-            var p2 = t2.children[c2];
-            o(s2, t2.leaf ? e3(p2) : p2), l2 += u(s2);
-          }
-          return l2;
-        }, r.prototype._adjustParentBBoxes = function(t2, i3, n3) {
-          for (var r2 = n3; r2 >= 0; r2--)
-            o(i3[r2], t2);
-        }, r.prototype._condense = function(t2) {
-          for (var i3 = t2.length - 1, n3 = void 0; i3 >= 0; i3--)
-            0 === t2[i3].children.length ? i3 > 0 ? (n3 = t2[i3 - 1].children).splice(n3.indexOf(t2[i3]), 1) : this.clear() : a(t2[i3], this.toBBox);
-        }, r;
-      });
-    }
-  });
-
-  // node_modules/ieee754/index.js
-  var require_ieee754 = __commonJS({
-    "node_modules/ieee754/index.js"(exports2) {
-      exports2.read = function(buffer, offset, isLE, mLen, nBytes) {
-        var e, m;
-        var eLen = nBytes * 8 - mLen - 1;
-        var eMax = (1 << eLen) - 1;
-        var eBias = eMax >> 1;
-        var nBits = -7;
-        var i2 = isLE ? nBytes - 1 : 0;
-        var d = isLE ? -1 : 1;
-        var s = buffer[offset + i2];
-        i2 += d;
-        e = s & (1 << -nBits) - 1;
-        s >>= -nBits;
-        nBits += eLen;
-        for (; nBits > 0; e = e * 256 + buffer[offset + i2], i2 += d, nBits -= 8) {
-        }
-        m = e & (1 << -nBits) - 1;
-        e >>= -nBits;
-        nBits += mLen;
-        for (; nBits > 0; m = m * 256 + buffer[offset + i2], i2 += d, nBits -= 8) {
-        }
-        if (e === 0) {
-          e = 1 - eBias;
-        } else if (e === eMax) {
-          return m ? NaN : (s ? -1 : 1) * Infinity;
-        } else {
-          m = m + Math.pow(2, mLen);
-          e = e - eBias;
-        }
-        return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
-      };
-      exports2.write = function(buffer, value, offset, isLE, mLen, nBytes) {
-        var e, m, c;
-        var eLen = nBytes * 8 - mLen - 1;
-        var eMax = (1 << eLen) - 1;
-        var eBias = eMax >> 1;
-        var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
-        var i2 = isLE ? 0 : nBytes - 1;
-        var d = isLE ? 1 : -1;
-        var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
-        value = Math.abs(value);
-        if (isNaN(value) || value === Infinity) {
-          m = isNaN(value) ? 1 : 0;
-          e = eMax;
-        } else {
-          e = Math.floor(Math.log(value) / Math.LN2);
-          if (value * (c = Math.pow(2, -e)) < 1) {
-            e--;
-            c *= 2;
-          }
-          if (e + eBias >= 1) {
-            value += rt / c;
-          } else {
-            value += rt * Math.pow(2, 1 - eBias);
-          }
-          if (value * c >= 2) {
-            e++;
-            c /= 2;
-          }
-          if (e + eBias >= eMax) {
-            m = 0;
-            e = eMax;
-          } else if (e + eBias >= 1) {
-            m = (value * c - 1) * Math.pow(2, mLen);
-            e = e + eBias;
-          } else {
-            m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
-            e = 0;
-          }
-        }
-        for (; mLen >= 8; buffer[offset + i2] = m & 255, i2 += d, m /= 256, mLen -= 8) {
-        }
-        e = e << mLen | m;
-        eLen += mLen;
-        for (; eLen > 0; buffer[offset + i2] = e & 255, i2 += d, e /= 256, eLen -= 8) {
-        }
-        buffer[offset + i2 - d] |= s * 128;
-      };
-    }
-  });
-
-  // node_modules/pbf/index.js
-  var require_pbf = __commonJS({
-    "node_modules/pbf/index.js"(exports2, module2) {
-      "use strict";
-      module2.exports = Pbf;
-      var ieee754 = require_ieee754();
-      function Pbf(buf) {
-        this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
-        this.pos = 0;
-        this.type = 0;
-        this.length = this.buf.length;
-      }
-      Pbf.Varint = 0;
-      Pbf.Fixed64 = 1;
-      Pbf.Bytes = 2;
-      Pbf.Fixed32 = 5;
-      var SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
-      var SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
-      var TEXT_DECODER_MIN_LENGTH = 12;
-      var utf8TextDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder("utf8");
-      Pbf.prototype = {
-        destroy: function() {
-          this.buf = null;
-        },
-        readFields: function(readField, result, end) {
-          end = end || this.length;
-          while (this.pos < end) {
-            var val = this.readVarint(), tag = val >> 3, startPos = this.pos;
-            this.type = val & 7;
-            readField(tag, result, this);
-            if (this.pos === startPos)
-              this.skip(val);
-          }
-          return result;
-        },
-        readMessage: function(readField, result) {
-          return this.readFields(readField, result, this.readVarint() + this.pos);
-        },
-        readFixed32: function() {
-          var val = readUInt32(this.buf, this.pos);
-          this.pos += 4;
-          return val;
-        },
-        readSFixed32: function() {
-          var val = readInt32(this.buf, this.pos);
-          this.pos += 4;
-          return val;
-        },
-        readFixed64: function() {
-          var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
-          this.pos += 8;
-          return val;
-        },
-        readSFixed64: function() {
-          var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
-          this.pos += 8;
-          return val;
-        },
-        readFloat: function() {
-          var val = ieee754.read(this.buf, this.pos, true, 23, 4);
-          this.pos += 4;
-          return val;
-        },
-        readDouble: function() {
-          var val = ieee754.read(this.buf, this.pos, true, 52, 8);
-          this.pos += 8;
-          return val;
-        },
-        readVarint: function(isSigned) {
-          var buf = this.buf, val, b;
-          b = buf[this.pos++];
-          val = b & 127;
-          if (b < 128)
-            return val;
-          b = buf[this.pos++];
-          val |= (b & 127) << 7;
-          if (b < 128)
-            return val;
-          b = buf[this.pos++];
-          val |= (b & 127) << 14;
-          if (b < 128)
-            return val;
-          b = buf[this.pos++];
-          val |= (b & 127) << 21;
-          if (b < 128)
-            return val;
-          b = buf[this.pos];
-          val |= (b & 15) << 28;
-          return readVarintRemainder(val, isSigned, this);
-        },
-        readVarint64: function() {
-          return this.readVarint(true);
-        },
-        readSVarint: function() {
-          var num = this.readVarint();
-          return num % 2 === 1 ? (num + 1) / -2 : num / 2;
-        },
-        readBoolean: function() {
-          return Boolean(this.readVarint());
-        },
-        readString: function() {
-          var end = this.readVarint() + this.pos;
-          var pos = this.pos;
-          this.pos = end;
-          if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
-            return readUtf8TextDecoder(this.buf, pos, end);
-          }
-          return readUtf8(this.buf, pos, end);
-        },
-        readBytes: function() {
-          var end = this.readVarint() + this.pos, buffer = this.buf.subarray(this.pos, end);
-          this.pos = end;
-          return buffer;
-        },
-        readPackedVarint: function(arr, isSigned) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readVarint(isSigned));
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readVarint(isSigned));
-          return arr;
-        },
-        readPackedSVarint: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readSVarint());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readSVarint());
-          return arr;
-        },
-        readPackedBoolean: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readBoolean());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readBoolean());
-          return arr;
-        },
-        readPackedFloat: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readFloat());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readFloat());
-          return arr;
-        },
-        readPackedDouble: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readDouble());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readDouble());
-          return arr;
-        },
-        readPackedFixed32: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readFixed32());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readFixed32());
-          return arr;
-        },
-        readPackedSFixed32: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readSFixed32());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readSFixed32());
-          return arr;
-        },
-        readPackedFixed64: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readFixed64());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readFixed64());
-          return arr;
-        },
-        readPackedSFixed64: function(arr) {
-          if (this.type !== Pbf.Bytes)
-            return arr.push(this.readSFixed64());
-          var end = readPackedEnd(this);
-          arr = arr || [];
-          while (this.pos < end)
-            arr.push(this.readSFixed64());
-          return arr;
-        },
-        skip: function(val) {
-          var type3 = val & 7;
-          if (type3 === Pbf.Varint)
-            while (this.buf[this.pos++] > 127) {
-            }
-          else if (type3 === Pbf.Bytes)
-            this.pos = this.readVarint() + this.pos;
-          else if (type3 === Pbf.Fixed32)
-            this.pos += 4;
-          else if (type3 === Pbf.Fixed64)
-            this.pos += 8;
-          else
-            throw new Error("Unimplemented type: " + type3);
-        },
-        writeTag: function(tag, type3) {
-          this.writeVarint(tag << 3 | type3);
-        },
-        realloc: function(min3) {
-          var length = this.length || 16;
-          while (length < this.pos + min3)
-            length *= 2;
-          if (length !== this.length) {
-            var buf = new Uint8Array(length);
-            buf.set(this.buf);
-            this.buf = buf;
-            this.length = length;
-          }
-        },
-        finish: function() {
-          this.length = this.pos;
-          this.pos = 0;
-          return this.buf.subarray(0, this.length);
-        },
-        writeFixed32: function(val) {
-          this.realloc(4);
-          writeInt32(this.buf, val, this.pos);
-          this.pos += 4;
-        },
-        writeSFixed32: function(val) {
-          this.realloc(4);
-          writeInt32(this.buf, val, this.pos);
-          this.pos += 4;
-        },
-        writeFixed64: function(val) {
-          this.realloc(8);
-          writeInt32(this.buf, val & -1, this.pos);
-          writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
-          this.pos += 8;
-        },
-        writeSFixed64: function(val) {
-          this.realloc(8);
-          writeInt32(this.buf, val & -1, this.pos);
-          writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
-          this.pos += 8;
-        },
-        writeVarint: function(val) {
-          val = +val || 0;
-          if (val > 268435455 || val < 0) {
-            writeBigVarint(val, this);
-            return;
-          }
-          this.realloc(4);
-          this.buf[this.pos++] = val & 127 | (val > 127 ? 128 : 0);
-          if (val <= 127)
-            return;
-          this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
-          if (val <= 127)
-            return;
-          this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
-          if (val <= 127)
-            return;
-          this.buf[this.pos++] = val >>> 7 & 127;
-        },
-        writeSVarint: function(val) {
-          this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
-        },
-        writeBoolean: function(val) {
-          this.writeVarint(Boolean(val));
-        },
-        writeString: function(str2) {
-          str2 = String(str2);
-          this.realloc(str2.length * 4);
-          this.pos++;
-          var startPos = this.pos;
-          this.pos = writeUtf8(this.buf, str2, this.pos);
-          var len = this.pos - startPos;
-          if (len >= 128)
-            makeRoomForExtraLength(startPos, len, this);
-          this.pos = startPos - 1;
-          this.writeVarint(len);
-          this.pos += len;
-        },
-        writeFloat: function(val) {
-          this.realloc(4);
-          ieee754.write(this.buf, val, this.pos, true, 23, 4);
-          this.pos += 4;
-        },
-        writeDouble: function(val) {
-          this.realloc(8);
-          ieee754.write(this.buf, val, this.pos, true, 52, 8);
-          this.pos += 8;
-        },
-        writeBytes: function(buffer) {
-          var len = buffer.length;
-          this.writeVarint(len);
-          this.realloc(len);
-          for (var i2 = 0; i2 < len; i2++)
-            this.buf[this.pos++] = buffer[i2];
-        },
-        writeRawMessage: function(fn, obj) {
-          this.pos++;
-          var startPos = this.pos;
-          fn(obj, this);
-          var len = this.pos - startPos;
-          if (len >= 128)
-            makeRoomForExtraLength(startPos, len, this);
-          this.pos = startPos - 1;
-          this.writeVarint(len);
-          this.pos += len;
-        },
-        writeMessage: function(tag, fn, obj) {
-          this.writeTag(tag, Pbf.Bytes);
-          this.writeRawMessage(fn, obj);
-        },
-        writePackedVarint: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedVarint, arr);
-        },
-        writePackedSVarint: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedSVarint, arr);
-        },
-        writePackedBoolean: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedBoolean, arr);
-        },
-        writePackedFloat: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedFloat, arr);
-        },
-        writePackedDouble: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedDouble, arr);
-        },
-        writePackedFixed32: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedFixed32, arr);
-        },
-        writePackedSFixed32: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedSFixed32, arr);
-        },
-        writePackedFixed64: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedFixed64, arr);
-        },
-        writePackedSFixed64: function(tag, arr) {
-          if (arr.length)
-            this.writeMessage(tag, writePackedSFixed64, arr);
-        },
-        writeBytesField: function(tag, buffer) {
-          this.writeTag(tag, Pbf.Bytes);
-          this.writeBytes(buffer);
-        },
-        writeFixed32Field: function(tag, val) {
-          this.writeTag(tag, Pbf.Fixed32);
-          this.writeFixed32(val);
-        },
-        writeSFixed32Field: function(tag, val) {
-          this.writeTag(tag, Pbf.Fixed32);
-          this.writeSFixed32(val);
-        },
-        writeFixed64Field: function(tag, val) {
-          this.writeTag(tag, Pbf.Fixed64);
-          this.writeFixed64(val);
-        },
-        writeSFixed64Field: function(tag, val) {
-          this.writeTag(tag, Pbf.Fixed64);
-          this.writeSFixed64(val);
-        },
-        writeVarintField: function(tag, val) {
-          this.writeTag(tag, Pbf.Varint);
-          this.writeVarint(val);
-        },
-        writeSVarintField: function(tag, val) {
-          this.writeTag(tag, Pbf.Varint);
-          this.writeSVarint(val);
-        },
-        writeStringField: function(tag, str2) {
-          this.writeTag(tag, Pbf.Bytes);
-          this.writeString(str2);
-        },
-        writeFloatField: function(tag, val) {
-          this.writeTag(tag, Pbf.Fixed32);
-          this.writeFloat(val);
-        },
-        writeDoubleField: function(tag, val) {
-          this.writeTag(tag, Pbf.Fixed64);
-          this.writeDouble(val);
-        },
-        writeBooleanField: function(tag, val) {
-          this.writeVarintField(tag, Boolean(val));
-        }
-      };
-      function readVarintRemainder(l, s, p) {
-        var buf = p.buf, h, b;
-        b = buf[p.pos++];
-        h = (b & 112) >> 4;
-        if (b < 128)
-          return toNum(l, h, s);
-        b = buf[p.pos++];
-        h |= (b & 127) << 3;
-        if (b < 128)
-          return toNum(l, h, s);
-        b = buf[p.pos++];
-        h |= (b & 127) << 10;
-        if (b < 128)
-          return toNum(l, h, s);
-        b = buf[p.pos++];
-        h |= (b & 127) << 17;
-        if (b < 128)
-          return toNum(l, h, s);
-        b = buf[p.pos++];
-        h |= (b & 127) << 24;
-        if (b < 128)
-          return toNum(l, h, s);
-        b = buf[p.pos++];
-        h |= (b & 1) << 31;
-        if (b < 128)
-          return toNum(l, h, s);
-        throw new Error("Expected varint not more than 10 bytes");
-      }
-      function readPackedEnd(pbf) {
-        return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
-      }
-      function toNum(low, high, isSigned) {
-        if (isSigned) {
-          return high * 4294967296 + (low >>> 0);
-        }
-        return (high >>> 0) * 4294967296 + (low >>> 0);
-      }
-      function writeBigVarint(val, pbf) {
-        var low, high;
-        if (val >= 0) {
-          low = val % 4294967296 | 0;
-          high = val / 4294967296 | 0;
-        } else {
-          low = ~(-val % 4294967296);
-          high = ~(-val / 4294967296);
-          if (low ^ 4294967295) {
-            low = low + 1 | 0;
-          } else {
-            low = 0;
-            high = high + 1 | 0;
-          }
-        }
-        if (val >= 18446744073709552e3 || val < -18446744073709552e3) {
-          throw new Error("Given varint doesn't fit into 10 bytes");
-        }
-        pbf.realloc(10);
-        writeBigVarintLow(low, high, pbf);
-        writeBigVarintHigh(high, pbf);
-      }
-      function writeBigVarintLow(low, high, pbf) {
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos++] = low & 127 | 128;
-        low >>>= 7;
-        pbf.buf[pbf.pos] = low & 127;
-      }
-      function writeBigVarintHigh(high, pbf) {
-        var lsb = (high & 7) << 4;
-        pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
-        if (!high)
-          return;
-        pbf.buf[pbf.pos++] = high & 127;
-      }
-      function makeRoomForExtraLength(startPos, len, pbf) {
-        var extraLen = len <= 16383 ? 1 : len <= 2097151 ? 2 : len <= 268435455 ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
-        pbf.realloc(extraLen);
-        for (var i2 = pbf.pos - 1; i2 >= startPos; i2--)
-          pbf.buf[i2 + extraLen] = pbf.buf[i2];
-      }
-      function writePackedVarint(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeVarint(arr[i2]);
-      }
-      function writePackedSVarint(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeSVarint(arr[i2]);
-      }
-      function writePackedFloat(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeFloat(arr[i2]);
-      }
-      function writePackedDouble(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeDouble(arr[i2]);
-      }
-      function writePackedBoolean(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeBoolean(arr[i2]);
-      }
-      function writePackedFixed32(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeFixed32(arr[i2]);
-      }
-      function writePackedSFixed32(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeSFixed32(arr[i2]);
-      }
-      function writePackedFixed64(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeFixed64(arr[i2]);
-      }
-      function writePackedSFixed64(arr, pbf) {
-        for (var i2 = 0; i2 < arr.length; i2++)
-          pbf.writeSFixed64(arr[i2]);
-      }
-      function readUInt32(buf, pos) {
-        return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 16777216;
-      }
-      function writeInt32(buf, val, pos) {
-        buf[pos] = val;
-        buf[pos + 1] = val >>> 8;
-        buf[pos + 2] = val >>> 16;
-        buf[pos + 3] = val >>> 24;
-      }
-      function readInt32(buf, pos) {
-        return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
-      }
-      function readUtf8(buf, pos, end) {
-        var str2 = "";
-        var i2 = pos;
-        while (i2 < end) {
-          var b0 = buf[i2];
-          var c = null;
-          var bytesPerSequence = b0 > 239 ? 4 : b0 > 223 ? 3 : b0 > 191 ? 2 : 1;
-          if (i2 + bytesPerSequence > end)
-            break;
-          var b1, b2, b3;
-          if (bytesPerSequence === 1) {
-            if (b0 < 128) {
-              c = b0;
-            }
-          } else if (bytesPerSequence === 2) {
-            b1 = buf[i2 + 1];
-            if ((b1 & 192) === 128) {
-              c = (b0 & 31) << 6 | b1 & 63;
-              if (c <= 127) {
-                c = null;
-              }
-            }
-          } else if (bytesPerSequence === 3) {
-            b1 = buf[i2 + 1];
-            b2 = buf[i2 + 2];
-            if ((b1 & 192) === 128 && (b2 & 192) === 128) {
-              c = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
-              if (c <= 2047 || c >= 55296 && c <= 57343) {
-                c = null;
-              }
-            }
-          } else if (bytesPerSequence === 4) {
-            b1 = buf[i2 + 1];
-            b2 = buf[i2 + 2];
-            b3 = buf[i2 + 3];
-            if ((b1 & 192) === 128 && (b2 & 192) === 128 && (b3 & 192) === 128) {
-              c = (b0 & 15) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
-              if (c <= 65535 || c >= 1114112) {
-                c = null;
-              }
-            }
-          }
-          if (c === null) {
-            c = 65533;
-            bytesPerSequence = 1;
-          } else if (c > 65535) {
-            c -= 65536;
-            str2 += String.fromCharCode(c >>> 10 & 1023 | 55296);
-            c = 56320 | c & 1023;
-          }
-          str2 += String.fromCharCode(c);
-          i2 += bytesPerSequence;
-        }
-        return str2;
-      }
-      function readUtf8TextDecoder(buf, pos, end) {
-        return utf8TextDecoder.decode(buf.subarray(pos, end));
-      }
-      function writeUtf8(buf, str2, pos) {
-        for (var i2 = 0, c, lead; i2 < str2.length; i2++) {
-          c = str2.charCodeAt(i2);
-          if (c > 55295 && c < 57344) {
-            if (lead) {
-              if (c < 56320) {
-                buf[pos++] = 239;
-                buf[pos++] = 191;
-                buf[pos++] = 189;
-                lead = c;
-                continue;
-              } else {
-                c = lead - 55296 << 10 | c - 56320 | 65536;
-                lead = null;
-              }
-            } else {
-              if (c > 56319 || i2 + 1 === str2.length) {
-                buf[pos++] = 239;
-                buf[pos++] = 191;
-                buf[pos++] = 189;
-              } else {
-                lead = c;
-              }
-              continue;
-            }
-          } else if (lead) {
-            buf[pos++] = 239;
-            buf[pos++] = 191;
-            buf[pos++] = 189;
-            lead = null;
-          }
-          if (c < 128) {
-            buf[pos++] = c;
-          } else {
-            if (c < 2048) {
-              buf[pos++] = c >> 6 | 192;
-            } else {
-              if (c < 65536) {
-                buf[pos++] = c >> 12 | 224;
-              } else {
-                buf[pos++] = c >> 18 | 240;
-                buf[pos++] = c >> 12 & 63 | 128;
-              }
-              buf[pos++] = c >> 6 & 63 | 128;
-            }
-            buf[pos++] = c & 63 | 128;
-          }
-        }
-        return pos;
-      }
-    }
-  });
-
-  // node_modules/@mapbox/point-geometry/index.js
-  var require_point_geometry = __commonJS({
-    "node_modules/@mapbox/point-geometry/index.js"(exports2, module2) {
-      "use strict";
-      module2.exports = Point;
-      function Point(x, y) {
-        this.x = x;
-        this.y = y;
-      }
-      Point.prototype = {
-        clone: function() {
-          return new Point(this.x, this.y);
-        },
-        add: function(p) {
-          return this.clone()._add(p);
-        },
-        sub: function(p) {
-          return this.clone()._sub(p);
-        },
-        multByPoint: function(p) {
-          return this.clone()._multByPoint(p);
-        },
-        divByPoint: function(p) {
-          return this.clone()._divByPoint(p);
-        },
-        mult: function(k) {
-          return this.clone()._mult(k);
-        },
-        div: function(k) {
-          return this.clone()._div(k);
-        },
-        rotate: function(a) {
-          return this.clone()._rotate(a);
-        },
-        rotateAround: function(a, p) {
-          return this.clone()._rotateAround(a, p);
-        },
-        matMult: function(m) {
-          return this.clone()._matMult(m);
-        },
-        unit: function() {
-          return this.clone()._unit();
-        },
-        perp: function() {
-          return this.clone()._perp();
-        },
-        round: function() {
-          return this.clone()._round();
-        },
-        mag: function() {
-          return Math.sqrt(this.x * this.x + this.y * this.y);
-        },
-        equals: function(other) {
-          return this.x === other.x && this.y === other.y;
-        },
-        dist: function(p) {
-          return Math.sqrt(this.distSqr(p));
-        },
-        distSqr: function(p) {
-          var dx = p.x - this.x, dy = p.y - this.y;
-          return dx * dx + dy * dy;
-        },
-        angle: function() {
-          return Math.atan2(this.y, this.x);
-        },
-        angleTo: function(b) {
-          return Math.atan2(this.y - b.y, this.x - b.x);
-        },
-        angleWith: function(b) {
-          return this.angleWithSep(b.x, b.y);
-        },
-        angleWithSep: function(x, y) {
-          return Math.atan2(
-            this.x * y - this.y * x,
-            this.x * x + this.y * y
-          );
-        },
-        _matMult: function(m) {
-          var x = m[0] * this.x + m[1] * this.y, y = m[2] * this.x + m[3] * this.y;
-          this.x = x;
-          this.y = y;
-          return this;
-        },
-        _add: function(p) {
-          this.x += p.x;
-          this.y += p.y;
-          return this;
-        },
-        _sub: function(p) {
-          this.x -= p.x;
-          this.y -= p.y;
-          return this;
-        },
-        _mult: function(k) {
-          this.x *= k;
-          this.y *= k;
-          return this;
-        },
-        _div: function(k) {
-          this.x /= k;
-          this.y /= k;
-          return this;
-        },
-        _multByPoint: function(p) {
-          this.x *= p.x;
-          this.y *= p.y;
-          return this;
-        },
-        _divByPoint: function(p) {
-          this.x /= p.x;
-          this.y /= p.y;
-          return this;
-        },
-        _unit: function() {
-          this._div(this.mag());
-          return this;
-        },
-        _perp: function() {
-          var y = this.y;
-          this.y = this.x;
-          this.x = -y;
-          return this;
-        },
-        _rotate: function(angle2) {
-          var cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x = cos2 * this.x - sin2 * this.y, y = sin2 * this.x + cos2 * this.y;
-          this.x = x;
-          this.y = y;
-          return this;
-        },
-        _rotateAround: function(angle2, p) {
-          var cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x = p.x + cos2 * (this.x - p.x) - sin2 * (this.y - p.y), y = p.y + sin2 * (this.x - p.x) + cos2 * (this.y - p.y);
-          this.x = x;
-          this.y = y;
-          return this;
-        },
-        _round: function() {
-          this.x = Math.round(this.x);
-          this.y = Math.round(this.y);
-          return this;
-        }
-      };
-      Point.convert = function(a) {
-        if (a instanceof Point) {
-          return a;
-        }
-        if (Array.isArray(a)) {
-          return new Point(a[0], a[1]);
-        }
-        return a;
-      };
-    }
-  });
-
-  // node_modules/@mapbox/vector-tile/lib/vectortilefeature.js
-  var require_vectortilefeature = __commonJS({
-    "node_modules/@mapbox/vector-tile/lib/vectortilefeature.js"(exports2, module2) {
+  // node_modules/fast-deep-equal/index.js
+  var require_fast_deep_equal = __commonJS({
+    "node_modules/fast-deep-equal/index.js"(exports2, module2) {
       "use strict";
-      var Point = require_point_geometry();
-      module2.exports = VectorTileFeature;
-      function VectorTileFeature(pbf, end, extent, keys, values) {
-        this.properties = {};
-        this.extent = extent;
-        this.type = 0;
-        this._pbf = pbf;
-        this._geometry = -1;
-        this._keys = keys;
-        this._values = values;
-        pbf.readFields(readFeature, this, end);
-      }
-      function readFeature(tag, feature3, pbf) {
-        if (tag == 1)
-          feature3.id = pbf.readVarint();
-        else if (tag == 2)
-          readTag(pbf, feature3);
-        else if (tag == 3)
-          feature3.type = pbf.readVarint();
-        else if (tag == 4)
-          feature3._geometry = pbf.pos;
-      }
-      function readTag(pbf, feature3) {
-        var end = pbf.readVarint() + pbf.pos;
-        while (pbf.pos < end) {
-          var key = feature3._keys[pbf.readVarint()], value = feature3._values[pbf.readVarint()];
-          feature3.properties[key] = value;
-        }
-      }
-      VectorTileFeature.types = ["Unknown", "Point", "LineString", "Polygon"];
-      VectorTileFeature.prototype.loadGeometry = function() {
-        var pbf = this._pbf;
-        pbf.pos = this._geometry;
-        var end = pbf.readVarint() + pbf.pos, cmd = 1, length = 0, x = 0, y = 0, lines = [], line;
-        while (pbf.pos < end) {
-          if (length <= 0) {
-            var cmdLen = pbf.readVarint();
-            cmd = cmdLen & 7;
-            length = cmdLen >> 3;
-          }
-          length--;
-          if (cmd === 1 || cmd === 2) {
-            x += pbf.readSVarint();
-            y += pbf.readSVarint();
-            if (cmd === 1) {
-              if (line)
-                lines.push(line);
-              line = [];
-            }
-            line.push(new Point(x, y));
-          } else if (cmd === 7) {
-            if (line) {
-              line.push(line[0].clone());
-            }
-          } else {
-            throw new Error("unknown command " + cmd);
-          }
-        }
-        if (line)
-          lines.push(line);
-        return lines;
-      };
-      VectorTileFeature.prototype.bbox = function() {
-        var pbf = this._pbf;
-        pbf.pos = this._geometry;
-        var end = pbf.readVarint() + pbf.pos, cmd = 1, length = 0, x = 0, y = 0, x12 = Infinity, x2 = -Infinity, y12 = Infinity, y2 = -Infinity;
-        while (pbf.pos < end) {
-          if (length <= 0) {
-            var cmdLen = pbf.readVarint();
-            cmd = cmdLen & 7;
-            length = cmdLen >> 3;
-          }
-          length--;
-          if (cmd === 1 || cmd === 2) {
-            x += pbf.readSVarint();
-            y += pbf.readSVarint();
-            if (x < x12)
-              x12 = x;
-            if (x > x2)
-              x2 = x;
-            if (y < y12)
-              y12 = y;
-            if (y > y2)
-              y2 = y;
-          } else if (cmd !== 7) {
-            throw new Error("unknown command " + cmd);
-          }
-        }
-        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;
-        function project(line) {
-          for (var j3 = 0; j3 < line.length; j3++) {
-            var p = line[j3], y2 = 180 - (p.y + y05) * 360 / size;
-            line[j3] = [
-              (p.x + x05) * 360 / size - 180,
-              360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
-            ];
+      module2.exports = function equal(a2, b2) {
+        if (a2 === b2) return true;
+        if (a2 && b2 && typeof a2 == "object" && typeof b2 == "object") {
+          if (a2.constructor !== b2.constructor) return false;
+          var length2, i3, keys2;
+          if (Array.isArray(a2)) {
+            length2 = a2.length;
+            if (length2 != b2.length) return false;
+            for (i3 = length2; i3-- !== 0; )
+              if (!equal(a2[i3], b2[i3])) return false;
+            return true;
           }
-        }
-        switch (this.type) {
-          case 1:
-            var points = [];
-            for (i2 = 0; i2 < coords.length; i2++) {
-              points[i2] = coords[i2][0];
-            }
-            coords = points;
-            project(coords);
-            break;
-          case 2:
-            for (i2 = 0; i2 < coords.length; i2++) {
-              project(coords[i2]);
-            }
-            break;
-          case 3:
-            coords = classifyRings(coords);
-            for (i2 = 0; i2 < coords.length; i2++) {
-              for (j2 = 0; j2 < coords[i2].length; j2++) {
-                project(coords[i2][j2]);
-              }
-            }
-            break;
-        }
-        if (coords.length === 1) {
-          coords = coords[0];
-        } else {
-          type3 = "Multi" + type3;
-        }
-        var result = {
-          type: "Feature",
-          geometry: {
-            type: type3,
-            coordinates: coords
-          },
-          properties: this.properties
-        };
-        if ("id" in this) {
-          result.id = this.id;
-        }
-        return result;
-      };
-      function classifyRings(rings) {
-        var len = rings.length;
-        if (len <= 1)
-          return [rings];
-        var polygons = [], polygon2, ccw;
-        for (var i2 = 0; i2 < len; i2++) {
-          var area = signedArea(rings[i2]);
-          if (area === 0)
-            continue;
-          if (ccw === void 0)
-            ccw = area < 0;
-          if (ccw === area < 0) {
-            if (polygon2)
-              polygons.push(polygon2);
-            polygon2 = [rings[i2]];
-          } else {
-            polygon2.push(rings[i2]);
+          if (a2.constructor === RegExp) return a2.source === b2.source && a2.flags === b2.flags;
+          if (a2.valueOf !== Object.prototype.valueOf) return a2.valueOf() === b2.valueOf();
+          if (a2.toString !== Object.prototype.toString) return a2.toString() === b2.toString();
+          keys2 = Object.keys(a2);
+          length2 = keys2.length;
+          if (length2 !== Object.keys(b2).length) return false;
+          for (i3 = length2; i3-- !== 0; )
+            if (!Object.prototype.hasOwnProperty.call(b2, keys2[i3])) return false;
+          for (i3 = length2; i3-- !== 0; ) {
+            var key = keys2[i3];
+            if (!equal(a2[key], b2[key])) return false;
           }
+          return true;
         }
-        if (polygon2)
-          polygons.push(polygon2);
-        return polygons;
-      }
-      function signedArea(ring) {
-        var sum = 0;
-        for (var i2 = 0, len = ring.length, j2 = len - 1, p1, p2; i2 < len; j2 = i2++) {
-          p1 = ring[i2];
-          p2 = ring[j2];
-          sum += (p2.x - p1.x) * (p1.y + p2.y);
-        }
-        return sum;
-      }
-    }
-  });
-
-  // node_modules/@mapbox/vector-tile/lib/vectortilelayer.js
-  var require_vectortilelayer = __commonJS({
-    "node_modules/@mapbox/vector-tile/lib/vectortilelayer.js"(exports2, module2) {
-      "use strict";
-      var VectorTileFeature = require_vectortilefeature();
-      module2.exports = VectorTileLayer;
-      function VectorTileLayer(pbf, end) {
-        this.version = 1;
-        this.name = null;
-        this.extent = 4096;
-        this.length = 0;
-        this._pbf = pbf;
-        this._keys = [];
-        this._values = [];
-        this._features = [];
-        pbf.readFields(readLayer, this, end);
-        this.length = this._features.length;
-      }
-      function readLayer(tag, layer, pbf) {
-        if (tag === 15)
-          layer.version = pbf.readVarint();
-        else if (tag === 1)
-          layer.name = pbf.readString();
-        else if (tag === 5)
-          layer.extent = pbf.readVarint();
-        else if (tag === 2)
-          layer._features.push(pbf.pos);
-        else if (tag === 3)
-          layer._keys.push(pbf.readString());
-        else if (tag === 4)
-          layer._values.push(readValueMessage(pbf));
-      }
-      function readValueMessage(pbf) {
-        var value = null, end = pbf.readVarint() + pbf.pos;
-        while (pbf.pos < end) {
-          var tag = pbf.readVarint() >> 3;
-          value = tag === 1 ? pbf.readString() : tag === 2 ? pbf.readFloat() : tag === 3 ? pbf.readDouble() : tag === 4 ? pbf.readVarint64() : tag === 5 ? pbf.readVarint() : tag === 6 ? pbf.readSVarint() : tag === 7 ? pbf.readBoolean() : null;
-        }
-        return value;
-      }
-      VectorTileLayer.prototype.feature = function(i2) {
-        if (i2 < 0 || i2 >= this._features.length)
-          throw new Error("feature index out of bounds");
-        this._pbf.pos = this._features[i2];
-        var end = this._pbf.readVarint() + this._pbf.pos;
-        return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
+        return a2 !== a2 && b2 !== b2;
       };
     }
   });
 
-  // node_modules/@mapbox/vector-tile/lib/vectortile.js
-  var require_vectortile = __commonJS({
-    "node_modules/@mapbox/vector-tile/lib/vectortile.js"(exports2, module2) {
-      "use strict";
-      var VectorTileLayer = require_vectortilelayer();
-      module2.exports = VectorTile2;
-      function VectorTile2(pbf, end) {
-        this.layers = pbf.readFields(readTile, {}, end);
-      }
-      function readTile(tag, layers, pbf) {
-        if (tag === 3) {
-          var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
-          if (layer.length)
-            layers[layer.name] = layer;
-        }
-      }
-    }
-  });
-
-  // node_modules/@mapbox/vector-tile/index.js
-  var require_vector_tile = __commonJS({
-    "node_modules/@mapbox/vector-tile/index.js"(exports2, module2) {
-      module2.exports.VectorTile = require_vectortile();
-      module2.exports.VectorTileFeature = require_vectortilefeature();
-      module2.exports.VectorTileLayer = require_vectortilelayer();
-    }
-  });
-
   // node_modules/fast-json-stable-stringify/index.js
   var require_fast_json_stable_stringify = __commonJS({
     "node_modules/fast-json-stable-stringify/index.js"(exports2, module2) {
       "use strict";
       module2.exports = function(data, opts) {
-        if (!opts)
-          opts = {};
-        if (typeof opts === "function")
-          opts = { cmp: opts };
+        if (!opts) opts = {};
+        if (typeof opts === "function") opts = { cmp: opts };
         var cycles = typeof opts.cycles === "boolean" ? opts.cycles : false;
-        var cmp = opts.cmp && function(f2) {
+        var cmp = opts.cmp && /* @__PURE__ */ function(f2) {
           return function(node) {
-            return function(a, b) {
-              var aobj = { key: a, value: node[a] };
-              var bobj = { key: b, value: node[b] };
+            return function(a2, b2) {
+              var aobj = { key: a2, value: node[a2] };
+              var bobj = { key: b2, value: node[b2] };
               return f2(aobj, bobj);
             };
           };
           if (node && node.toJSON && typeof node.toJSON === "function") {
             node = node.toJSON();
           }
-          if (node === void 0)
-            return;
-          if (typeof node == "number")
-            return isFinite(node) ? "" + node : "null";
-          if (typeof node !== "object")
-            return JSON.stringify(node);
-          var i2, out;
+          if (node === void 0) return;
+          if (typeof node == "number") return isFinite(node) ? "" + node : "null";
+          if (typeof node !== "object") return JSON.stringify(node);
+          var i3, out;
           if (Array.isArray(node)) {
             out = "[";
-            for (i2 = 0; i2 < node.length; i2++) {
-              if (i2)
-                out += ",";
-              out += stringify3(node[i2]) || "null";
+            for (i3 = 0; i3 < node.length; i3++) {
+              if (i3) out += ",";
+              out += stringify3(node[i3]) || "null";
             }
             return out + "]";
           }
-          if (node === null)
-            return "null";
+          if (node === null) return "null";
           if (seen.indexOf(node) !== -1) {
-            if (cycles)
-              return JSON.stringify("__cycle__");
+            if (cycles) return JSON.stringify("__cycle__");
             throw new TypeError("Converting circular structure to JSON");
           }
           var seenIndex = seen.push(node) - 1;
-          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 (i3 = 0; i3 < keys2.length; i3++) {
+            var key = keys2[i3];
             var value = stringify3(node[key]);
-            if (!value)
-              continue;
-            if (out)
-              out += ",";
+            if (!value) continue;
+            if (out) out += ",";
             out += JSON.stringify(key) + ":" + value;
           }
           seen.splice(seenIndex, 1);
   var require_sexagesimal = __commonJS({
     "node_modules/@mapbox/sexagesimal/index.js"(exports2, module2) {
       module2.exports = element;
-      module2.exports.pair = pair2;
+      module2.exports.pair = pair3;
       module2.exports.format = format2;
       module2.exports.formatPair = formatPair;
       module2.exports.coordToDMS = coordToDMS;
         };
       }
       function search(input, dims) {
-        if (!dims)
-          dims = "NSEW";
-        if (typeof input !== "string")
-          return null;
+        if (!dims) dims = "NSEW";
+        if (typeof input !== "string") return null;
         input = input.toUpperCase();
         var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
-        var m = input.match(regex);
-        if (!m)
-          return null;
-        var matched = m[0];
+        var m2 = input.match(regex);
+        if (!m2) return null;
+        var matched = m2[0];
         var dim;
-        if (m[1] && m[5]) {
-          dim = m[1];
+        if (m2[1] && m2[5]) {
+          dim = m2[1];
           matched = matched.slice(0, -1);
         } else {
-          dim = m[1] || m[5];
+          dim = m2[1] || m2[5];
         }
-        if (dim && dims.indexOf(dim) === -1)
-          return null;
-        var deg = m[2] ? parseFloat(m[2]) : 0;
-        var min3 = m[3] ? parseFloat(m[3]) / 60 : 0;
-        var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
+        if (dim && dims.indexOf(dim) === -1) return null;
+        var deg = m2[2] ? parseFloat(m2[2]) : 0;
+        var min3 = m2[3] ? parseFloat(m2[3]) / 60 : 0;
+        var sec = m2[4] ? parseFloat(m2[4]) / 3600 : 0;
         var sign2 = deg < 0 ? -1 : 1;
-        if (dim === "S" || dim === "W")
-          sign2 *= -1;
+        if (dim === "S" || dim === "W") sign2 *= -1;
         return {
           val: (Math.abs(deg) + min3 + sec) * sign2,
           dim,
           remain: input.slice(matched.length)
         };
       }
-      function pair2(input, dims) {
+      function pair3(input, dims) {
         input = input.trim();
         var one2 = search(input, dims);
-        if (!one2)
-          return null;
+        if (!one2) return null;
         input = one2.remain.trim();
         var two = search(input, dims);
-        if (!two || two.remain)
-          return null;
+        if (!two || two.remain) return null;
         if (one2.dim) {
           return swapdim(one2.val, two.val, one2.dim);
         } else {
           return [one2.val, two.val];
         }
       }
-      function swapdim(a, b, dim) {
-        if (dim === "N" || dim === "S")
-          return [a, b];
-        if (dim === "W" || dim === "E")
-          return [b, a];
+      function swapdim(a2, b2, dim) {
+        if (dim === "N" || dim === "S") return [a2, b2];
+        if (dim === "W" || dim === "E") return [b2, a2];
       }
     }
   });
 
-  // node_modules/store/src/util.js
-  var require_util = __commonJS({
-    "node_modules/store/src/util.js"(exports2, module2) {
-      var assign = make_assign();
-      var create2 = make_create();
-      var trim = make_trim();
-      var Global = typeof window !== "undefined" ? window : global;
-      module2.exports = {
-        assign,
-        create: create2,
-        trim,
-        bind,
-        slice,
-        each,
-        map: map2,
-        pluck,
-        isList,
-        isFunction,
-        isObject: isObject2,
-        Global
-      };
-      function make_assign() {
-        if (Object.assign) {
-          return Object.assign;
-        } else {
-          return function shimAssign(obj, props1, props2, etc) {
-            for (var i2 = 1; i2 < arguments.length; i2++) {
-              each(Object(arguments[i2]), function(val, key) {
-                obj[key] = val;
-              });
-            }
-            return obj;
-          };
-        }
-      }
-      function make_create() {
-        if (Object.create) {
-          return function create3(obj, assignProps1, assignProps2, etc) {
-            var assignArgsList = slice(arguments, 1);
-            return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
-          };
-        } else {
-          let F2 = function() {
-          };
-          var F = F2;
-          return function create3(obj, assignProps1, assignProps2, etc) {
-            var assignArgsList = slice(arguments, 1);
-            F2.prototype = obj;
-            return assign.apply(this, [new F2()].concat(assignArgsList));
-          };
-        }
-      }
-      function make_trim() {
-        if (String.prototype.trim) {
-          return function trim2(str2) {
-            return String.prototype.trim.call(str2);
-          };
-        } else {
-          return function trim2(str2) {
-            return str2.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
-          };
-        }
-      }
-      function bind(obj, fn) {
-        return function() {
-          return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
-        };
-      }
-      function slice(arr, index) {
-        return Array.prototype.slice.call(arr, index || 0);
-      }
-      function each(obj, fn) {
-        pluck(obj, function(val, key) {
-          fn(val, key);
-          return false;
-        });
-      }
-      function map2(obj, fn) {
-        var res = isList(obj) ? [] : {};
-        pluck(obj, function(v, k) {
-          res[k] = fn(v, k);
-          return false;
-        });
-        return res;
-      }
-      function pluck(obj, fn) {
-        if (isList(obj)) {
-          for (var i2 = 0; i2 < obj.length; i2++) {
-            if (fn(obj[i2], i2)) {
-              return obj[i2];
-            }
+  // node_modules/polygon-clipping/dist/polygon-clipping.umd.js
+  var require_polygon_clipping_umd = __commonJS({
+    "node_modules/polygon-clipping/dist/polygon-clipping.umd.js"(exports2, module2) {
+      (function(global2, factory) {
+        typeof exports2 === "object" && typeof module2 !== "undefined" ? module2.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, global2.polygonClipping = factory());
+      })(exports2, function() {
+        "use strict";
+        function __generator(thisArg, body) {
+          var _2 = {
+            label: 0,
+            sent: function() {
+              if (t2[0] & 1) throw t2[1];
+              return t2[1];
+            },
+            trys: [],
+            ops: []
+          }, f2, y2, t2, g3;
+          return g3 = {
+            next: verb(0),
+            "throw": verb(1),
+            "return": verb(2)
+          }, typeof Symbol === "function" && (g3[Symbol.iterator] = function() {
+            return this;
+          }), g3;
+          function verb(n3) {
+            return function(v2) {
+              return step([n3, v2]);
+            };
           }
-        } else {
-          for (var key in obj) {
-            if (obj.hasOwnProperty(key)) {
-              if (fn(obj[key], key)) {
-                return obj[key];
+          function step(op) {
+            if (f2) throw new TypeError("Generator is already executing.");
+            while (_2) try {
+              if (f2 = 1, y2 && (t2 = op[0] & 2 ? y2["return"] : op[0] ? y2["throw"] || ((t2 = y2["return"]) && t2.call(y2), 0) : y2.next) && !(t2 = t2.call(y2, op[1])).done) return t2;
+              if (y2 = 0, t2) op = [op[0] & 2, t2.value];
+              switch (op[0]) {
+                case 0:
+                case 1:
+                  t2 = op;
+                  break;
+                case 4:
+                  _2.label++;
+                  return {
+                    value: op[1],
+                    done: false
+                  };
+                case 5:
+                  _2.label++;
+                  y2 = op[1];
+                  op = [0];
+                  continue;
+                case 7:
+                  op = _2.ops.pop();
+                  _2.trys.pop();
+                  continue;
+                default:
+                  if (!(t2 = _2.trys, t2 = t2.length > 0 && t2[t2.length - 1]) && (op[0] === 6 || op[0] === 2)) {
+                    _2 = 0;
+                    continue;
+                  }
+                  if (op[0] === 3 && (!t2 || op[1] > t2[0] && op[1] < t2[3])) {
+                    _2.label = op[1];
+                    break;
+                  }
+                  if (op[0] === 6 && _2.label < t2[1]) {
+                    _2.label = t2[1];
+                    t2 = op;
+                    break;
+                  }
+                  if (t2 && _2.label < t2[2]) {
+                    _2.label = t2[2];
+                    _2.ops.push(op);
+                    break;
+                  }
+                  if (t2[2]) _2.ops.pop();
+                  _2.trys.pop();
+                  continue;
               }
-            }
+              op = body.call(thisArg, _2);
+            } catch (e3) {
+              op = [6, e3];
+              y2 = 0;
+            } finally {
+              f2 = t2 = 0;
+            }
+            if (op[0] & 5) throw op[1];
+            return {
+              value: op[0] ? op[1] : void 0,
+              done: true
+            };
           }
         }
-      }
-      function isList(val) {
-        return val != null && typeof val != "function" && typeof val.length == "number";
-      }
-      function isFunction(val) {
-        return val && {}.toString.call(val) === "[object Function]";
-      }
-      function isObject2(val) {
-        return val && {}.toString.call(val) === "[object Object]";
-      }
-    }
-  });
-
-  // node_modules/store/src/store-engine.js
-  var require_store_engine = __commonJS({
-    "node_modules/store/src/store-engine.js"(exports2, module2) {
-      var util = require_util();
-      var slice = util.slice;
-      var pluck = util.pluck;
-      var each = util.each;
-      var bind = util.bind;
-      var create2 = util.create;
-      var isList = util.isList;
-      var isFunction = util.isFunction;
-      var isObject2 = util.isObject;
-      module2.exports = {
-        createStore
-      };
-      var storeAPI = {
-        version: "2.0.12",
-        enabled: false,
-        get: function(key, optionalDefaultValue) {
-          var data = this.storage.read(this._namespacePrefix + key);
-          return this._deserialize(data, optionalDefaultValue);
-        },
-        set: function(key, value) {
-          if (value === void 0) {
-            return this.remove(key);
-          }
-          this.storage.write(this._namespacePrefix + key, this._serialize(value));
-          return value;
-        },
-        remove: function(key) {
-          this.storage.remove(this._namespacePrefix + key);
-        },
-        each: function(callback) {
-          var self2 = this;
-          this.storage.each(function(val, namespacedKey) {
-            callback.call(self2, self2._deserialize(val), (namespacedKey || "").replace(self2._namespaceRegexp, ""));
-          });
-        },
-        clearAll: function() {
-          this.storage.clearAll();
-        },
-        hasNamespace: function(namespace) {
-          return this._namespacePrefix == "__storejs_" + namespace + "_";
-        },
-        createStore: function() {
-          return createStore.apply(this, arguments);
-        },
-        addPlugin: function(plugin) {
-          this._addPlugin(plugin);
-        },
-        namespace: function(namespace) {
-          return createStore(this.storage, this.plugins, namespace);
-        }
-      };
-      function _warn() {
-        var _console = typeof console == "undefined" ? null : console;
-        if (!_console) {
-          return;
-        }
-        var fn = _console.warn ? _console.warn : _console.log;
-        fn.apply(_console, arguments);
-      }
-      function createStore(storages, plugins, namespace) {
-        if (!namespace) {
-          namespace = "";
-        }
-        if (storages && !isList(storages)) {
-          storages = [storages];
-        }
-        if (plugins && !isList(plugins)) {
-          plugins = [plugins];
-        }
-        var namespacePrefix = namespace ? "__storejs_" + namespace + "_" : "";
-        var namespaceRegexp = namespace ? new RegExp("^" + namespacePrefix) : null;
-        var legalNamespaces = /^[a-zA-Z0-9_\-]*$/;
-        if (!legalNamespaces.test(namespace)) {
-          throw new Error("store.js namespaces can only have alphanumerics + underscores and dashes");
-        }
-        var _privateStoreProps = {
-          _namespacePrefix: namespacePrefix,
-          _namespaceRegexp: namespaceRegexp,
-          _testStorage: function(storage) {
-            try {
-              var testStr = "__storejs__test__";
-              storage.write(testStr, testStr);
-              var ok = storage.read(testStr) === testStr;
-              storage.remove(testStr);
-              return ok;
-            } catch (e) {
-              return false;
+        var Node = (
+          /** @class */
+          /* @__PURE__ */ function() {
+            function Node2(key, data) {
+              this.next = null;
+              this.key = key;
+              this.data = data;
+              this.left = null;
+              this.right = null;
             }
-          },
-          _assignPluginFnProp: function(pluginFnProp, propName) {
-            var oldFn = this[propName];
-            this[propName] = function pluginFn() {
-              var args = slice(arguments, 0);
-              var self2 = this;
-              function super_fn() {
-                if (!oldFn) {
-                  return;
-                }
-                each(arguments, function(arg, i2) {
-                  args[i2] = arg;
-                });
-                return oldFn.apply(self2, args);
+            return Node2;
+          }()
+        );
+        function DEFAULT_COMPARE(a2, b2) {
+          return a2 > b2 ? 1 : a2 < b2 ? -1 : 0;
+        }
+        function splay(i3, t2, comparator) {
+          var N2 = new Node(null, null);
+          var l2 = N2;
+          var r2 = N2;
+          while (true) {
+            var cmp2 = comparator(i3, t2.key);
+            if (cmp2 < 0) {
+              if (t2.left === null) break;
+              if (comparator(i3, t2.left.key) < 0) {
+                var y2 = t2.left;
+                t2.left = y2.right;
+                y2.right = t2;
+                t2 = y2;
+                if (t2.left === null) break;
               }
-              var newFnArgs = [super_fn].concat(args);
-              return pluginFnProp.apply(self2, newFnArgs);
-            };
-          },
-          _serialize: function(obj) {
-            return JSON.stringify(obj);
-          },
-          _deserialize: function(strVal, defaultVal) {
-            if (!strVal) {
-              return defaultVal;
-            }
-            var val = "";
-            try {
-              val = JSON.parse(strVal);
-            } catch (e) {
-              val = strVal;
-            }
-            return val !== void 0 ? val : defaultVal;
-          },
-          _addStorage: function(storage) {
-            if (this.enabled) {
-              return;
-            }
-            if (this._testStorage(storage)) {
-              this.storage = storage;
-              this.enabled = true;
-            }
-          },
-          _addPlugin: function(plugin) {
-            var self2 = this;
-            if (isList(plugin)) {
-              each(plugin, function(plugin2) {
-                self2._addPlugin(plugin2);
-              });
-              return;
-            }
-            var seenPlugin = pluck(this.plugins, function(seenPlugin2) {
-              return plugin === seenPlugin2;
-            });
-            if (seenPlugin) {
-              return;
-            }
-            this.plugins.push(plugin);
-            if (!isFunction(plugin)) {
-              throw new Error("Plugins must be function values that return objects");
-            }
-            var pluginProperties = plugin.call(this);
-            if (!isObject2(pluginProperties)) {
-              throw new Error("Plugins must return an object of function properties");
-            }
-            each(pluginProperties, function(pluginFnProp, propName) {
-              if (!isFunction(pluginFnProp)) {
-                throw new Error("Bad plugin property: " + propName + " from plugin " + plugin.name + ". Plugins should only return functions.");
+              r2.left = t2;
+              r2 = t2;
+              t2 = t2.left;
+            } else if (cmp2 > 0) {
+              if (t2.right === null) break;
+              if (comparator(i3, t2.right.key) > 0) {
+                var y2 = t2.right;
+                t2.right = y2.left;
+                y2.left = t2;
+                t2 = y2;
+                if (t2.right === null) break;
               }
-              self2._assignPluginFnProp(pluginFnProp, propName);
-            });
-          },
-          addStorage: function(storage) {
-            _warn("store.addStorage(storage) is deprecated. Use createStore([storages])");
-            this._addStorage(storage);
-          }
-        };
-        var store2 = create2(_privateStoreProps, storeAPI, {
-          plugins: []
-        });
-        store2.raw = {};
-        each(store2, function(prop, propName) {
-          if (isFunction(prop)) {
-            store2.raw[propName] = bind(store2, prop);
-          }
-        });
-        each(storages, function(storage) {
-          store2._addStorage(storage);
-        });
-        each(plugins, function(plugin) {
-          store2._addPlugin(plugin);
-        });
-        return store2;
-      }
-    }
-  });
-
-  // node_modules/store/storages/localStorage.js
-  var require_localStorage = __commonJS({
-    "node_modules/store/storages/localStorage.js"(exports2, module2) {
-      var util = require_util();
-      var Global = util.Global;
-      module2.exports = {
-        name: "localStorage",
-        read,
-        write,
-        each,
-        remove: remove2,
-        clearAll
-      };
-      function localStorage2() {
-        return Global.localStorage;
-      }
-      function read(key) {
-        return localStorage2().getItem(key);
-      }
-      function write(key, data) {
-        return localStorage2().setItem(key, data);
-      }
-      function each(fn) {
-        for (var i2 = localStorage2().length - 1; i2 >= 0; i2--) {
-          var key = localStorage2().key(i2);
-          fn(read(key), key);
-        }
-      }
-      function remove2(key) {
-        return localStorage2().removeItem(key);
-      }
-      function clearAll() {
-        return localStorage2().clear();
-      }
-    }
-  });
-
-  // node_modules/store/storages/oldFF-globalStorage.js
-  var require_oldFF_globalStorage = __commonJS({
-    "node_modules/store/storages/oldFF-globalStorage.js"(exports2, module2) {
-      var util = require_util();
-      var Global = util.Global;
-      module2.exports = {
-        name: "oldFF-globalStorage",
-        read,
-        write,
-        each,
-        remove: remove2,
-        clearAll
-      };
-      var globalStorage = Global.globalStorage;
-      function read(key) {
-        return globalStorage[key];
-      }
-      function write(key, data) {
-        globalStorage[key] = data;
-      }
-      function each(fn) {
-        for (var i2 = globalStorage.length - 1; i2 >= 0; i2--) {
-          var key = globalStorage.key(i2);
-          fn(globalStorage[key], key);
-        }
-      }
-      function remove2(key) {
-        return globalStorage.removeItem(key);
-      }
-      function clearAll() {
-        each(function(key, _) {
-          delete globalStorage[key];
-        });
-      }
-    }
-  });
-
-  // node_modules/store/storages/oldIE-userDataStorage.js
-  var require_oldIE_userDataStorage = __commonJS({
-    "node_modules/store/storages/oldIE-userDataStorage.js"(exports2, module2) {
-      var util = require_util();
-      var Global = util.Global;
-      module2.exports = {
-        name: "oldIE-userDataStorage",
-        write,
-        read,
-        each,
-        remove: remove2,
-        clearAll
-      };
-      var storageName = "storejs";
-      var doc = Global.document;
-      var _withStorageEl = _makeIEStorageElFunction();
-      var disable = (Global.navigator ? Global.navigator.userAgent : "").match(/ (MSIE 8|MSIE 9|MSIE 10)\./);
-      function write(unfixedKey, data) {
-        if (disable) {
-          return;
-        }
-        var fixedKey = fixKey(unfixedKey);
-        _withStorageEl(function(storageEl) {
-          storageEl.setAttribute(fixedKey, data);
-          storageEl.save(storageName);
-        });
-      }
-      function read(unfixedKey) {
-        if (disable) {
-          return;
+              l2.right = t2;
+              l2 = t2;
+              t2 = t2.right;
+            } else break;
+          }
+          l2.right = t2.left;
+          r2.left = t2.right;
+          t2.left = N2.right;
+          t2.right = N2.left;
+          return t2;
         }
-        var fixedKey = fixKey(unfixedKey);
-        var res = null;
-        _withStorageEl(function(storageEl) {
-          res = storageEl.getAttribute(fixedKey);
-        });
-        return res;
-      }
-      function each(callback) {
-        _withStorageEl(function(storageEl) {
-          var attributes = storageEl.XMLDocument.documentElement.attributes;
-          for (var i2 = attributes.length - 1; i2 >= 0; i2--) {
-            var attr = attributes[i2];
-            callback(storageEl.getAttribute(attr.name), attr.name);
+        function insert(i3, data, t2, comparator) {
+          var node = new Node(i3, data);
+          if (t2 === null) {
+            node.left = node.right = null;
+            return node;
           }
-        });
-      }
-      function remove2(unfixedKey) {
-        var fixedKey = fixKey(unfixedKey);
-        _withStorageEl(function(storageEl) {
-          storageEl.removeAttribute(fixedKey);
-          storageEl.save(storageName);
-        });
-      }
-      function clearAll() {
-        _withStorageEl(function(storageEl) {
-          var attributes = storageEl.XMLDocument.documentElement.attributes;
-          storageEl.load(storageName);
-          for (var i2 = attributes.length - 1; i2 >= 0; i2--) {
-            storageEl.removeAttribute(attributes[i2].name);
+          t2 = splay(i3, t2, comparator);
+          var cmp2 = comparator(i3, t2.key);
+          if (cmp2 < 0) {
+            node.left = t2.left;
+            node.right = t2;
+            t2.left = null;
+          } else if (cmp2 >= 0) {
+            node.right = t2.right;
+            node.left = t2;
+            t2.right = null;
           }
-          storageEl.save(storageName);
-        });
-      }
-      var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
-      function fixKey(key) {
-        return key.replace(/^\d/, "___$&").replace(forbiddenCharsRegex, "___");
-      }
-      function _makeIEStorageElFunction() {
-        if (!doc || !doc.documentElement || !doc.documentElement.addBehavior) {
-          return null;
-        }
-        var scriptTag = "script", storageOwner, storageContainer, storageEl;
-        try {
-          storageContainer = new ActiveXObject("htmlfile");
-          storageContainer.open();
-          storageContainer.write("<" + scriptTag + ">document.w=window</" + scriptTag + '><iframe src="/favicon.ico"></iframe>');
-          storageContainer.close();
-          storageOwner = storageContainer.w.frames[0].document;
-          storageEl = storageOwner.createElement("div");
-        } catch (e) {
-          storageEl = doc.createElement("div");
-          storageOwner = doc.body;
-        }
-        return function(storeFunction) {
-          var args = [].slice.call(arguments, 0);
-          args.unshift(storageEl);
-          storageOwner.appendChild(storageEl);
-          storageEl.addBehavior("#default#userData");
-          storageEl.load(storageName);
-          storeFunction.apply(this, args);
-          storageOwner.removeChild(storageEl);
-          return;
-        };
-      }
-    }
-  });
-
-  // node_modules/store/storages/cookieStorage.js
-  var require_cookieStorage = __commonJS({
-    "node_modules/store/storages/cookieStorage.js"(exports2, module2) {
-      var util = require_util();
-      var Global = util.Global;
-      var trim = util.trim;
-      module2.exports = {
-        name: "cookieStorage",
-        read,
-        write,
-        each,
-        remove: remove2,
-        clearAll
-      };
-      var doc = Global.document;
-      function read(key) {
-        if (!key || !_has(key)) {
-          return null;
+          return node;
         }
-        var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
-        return unescape(doc.cookie.replace(new RegExp(regexpStr), "$1"));
-      }
-      function each(callback) {
-        var cookies = doc.cookie.split(/; ?/g);
-        for (var i2 = cookies.length - 1; i2 >= 0; i2--) {
-          if (!trim(cookies[i2])) {
-            continue;
+        function split(key, v2, comparator) {
+          var left = null;
+          var right = null;
+          if (v2) {
+            v2 = splay(key, v2, comparator);
+            var cmp2 = comparator(v2.key, key);
+            if (cmp2 === 0) {
+              left = v2.left;
+              right = v2.right;
+            } else if (cmp2 < 0) {
+              right = v2.right;
+              v2.right = null;
+              left = v2;
+            } else {
+              left = v2.left;
+              v2.left = null;
+              right = v2;
+            }
           }
-          var kvp = cookies[i2].split("=");
-          var key = unescape(kvp[0]);
-          var val = unescape(kvp[1]);
-          callback(val, key);
-        }
-      }
-      function write(key, data) {
-        if (!key) {
-          return;
-        }
-        doc.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
-      }
-      function remove2(key) {
-        if (!key || !_has(key)) {
-          return;
+          return {
+            left,
+            right
+          };
         }
-        doc.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
-      }
-      function clearAll() {
-        each(function(_, key) {
-          remove2(key);
-        });
-      }
-      function _has(key) {
-        return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc.cookie);
-      }
-    }
-  });
-
-  // node_modules/store/storages/sessionStorage.js
-  var require_sessionStorage = __commonJS({
-    "node_modules/store/storages/sessionStorage.js"(exports2, module2) {
-      var util = require_util();
-      var Global = util.Global;
-      module2.exports = {
-        name: "sessionStorage",
-        read,
-        write,
-        each,
-        remove: remove2,
-        clearAll
-      };
-      function sessionStorage() {
-        return Global.sessionStorage;
-      }
-      function read(key) {
-        return sessionStorage().getItem(key);
-      }
-      function write(key, data) {
-        return sessionStorage().setItem(key, data);
-      }
-      function each(fn) {
-        for (var i2 = sessionStorage().length - 1; i2 >= 0; i2--) {
-          var key = sessionStorage().key(i2);
-          fn(read(key), key);
+        function merge2(left, right, comparator) {
+          if (right === null) return left;
+          if (left === null) return right;
+          right = splay(left.key, right, comparator);
+          right.left = left;
+          return right;
         }
-      }
-      function remove2(key) {
-        return sessionStorage().removeItem(key);
-      }
-      function clearAll() {
-        return sessionStorage().clear();
-      }
-    }
-  });
-
-  // node_modules/store/storages/memoryStorage.js
-  var require_memoryStorage = __commonJS({
-    "node_modules/store/storages/memoryStorage.js"(exports2, module2) {
-      module2.exports = {
-        name: "memoryStorage",
-        read,
-        write,
-        each,
-        remove: remove2,
-        clearAll
-      };
-      var memoryStorage = {};
-      function read(key) {
-        return memoryStorage[key];
-      }
-      function write(key, data) {
-        memoryStorage[key] = data;
-      }
-      function each(callback) {
-        for (var key in memoryStorage) {
-          if (memoryStorage.hasOwnProperty(key)) {
-            callback(memoryStorage[key], key);
+        function printRow(root3, prefix, isTail, out, printNode) {
+          if (root3) {
+            out("" + prefix + (isTail ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ") + printNode(root3) + "\n");
+            var indent = prefix + (isTail ? "    " : "\u2502   ");
+            if (root3.left) printRow(root3.left, indent, false, out, printNode);
+            if (root3.right) printRow(root3.right, indent, true, out, printNode);
           }
         }
-      }
-      function remove2(key) {
-        delete memoryStorage[key];
-      }
-      function clearAll(key) {
-        memoryStorage = {};
-      }
-    }
-  });
-
-  // node_modules/store/storages/all.js
-  var require_all = __commonJS({
-    "node_modules/store/storages/all.js"(exports2, module2) {
-      module2.exports = [
-        require_localStorage(),
-        require_oldFF_globalStorage(),
-        require_oldIE_userDataStorage(),
-        require_cookieStorage(),
-        require_sessionStorage(),
-        require_memoryStorage()
-      ];
-    }
-  });
-
-  // node_modules/store/plugins/lib/json2.js
-  var require_json2 = __commonJS({
-    "node_modules/store/plugins/lib/json2.js"(exports, module) {
-      if (typeof JSON !== "object") {
-        JSON = {};
-      }
-      (function() {
-        "use strict";
-        var rx_one = /^[\],:{}\s]*$/;
-        var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
-        var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
-        var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
-        var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-        var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-        function f(n2) {
-          return n2 < 10 ? "0" + n2 : n2;
-        }
-        function this_value() {
-          return this.valueOf();
-        }
-        if (typeof Date.prototype.toJSON !== "function") {
-          Date.prototype.toJSON = function() {
-            return isFinite(this.valueOf()) ? this.getUTCFullYear() + "-" + f(this.getUTCMonth() + 1) + "-" + f(this.getUTCDate()) + "T" + f(this.getUTCHours()) + ":" + f(this.getUTCMinutes()) + ":" + f(this.getUTCSeconds()) + "Z" : null;
-          };
-          Boolean.prototype.toJSON = this_value;
-          Number.prototype.toJSON = this_value;
-          String.prototype.toJSON = this_value;
-        }
-        var gap;
-        var indent;
-        var meta;
-        var rep;
-        function quote(string) {
-          rx_escapable.lastIndex = 0;
-          return rx_escapable.test(string) ? '"' + string.replace(rx_escapable, function(a) {
-            var c = meta[a];
-            return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
-          }) + '"' : '"' + string + '"';
-        }
-        function str(key, holder) {
-          var i2;
-          var k;
-          var v;
-          var length;
-          var mind = gap;
-          var partial;
-          var value = holder[key];
-          if (value && typeof value === "object" && typeof value.toJSON === "function") {
-            value = value.toJSON(key);
-          }
-          if (typeof rep === "function") {
-            value = rep.call(holder, key, value);
-          }
-          switch (typeof value) {
-            case "string":
-              return quote(value);
-            case "number":
-              return isFinite(value) ? String(value) : "null";
-            case "boolean":
-            case "null":
-              return String(value);
-            case "object":
-              if (!value) {
-                return "null";
+        var Tree = (
+          /** @class */
+          function() {
+            function Tree2(comparator) {
+              if (comparator === void 0) {
+                comparator = DEFAULT_COMPARE;
               }
-              gap += indent;
-              partial = [];
-              if (Object.prototype.toString.apply(value) === "[object Array]") {
-                length = value.length;
-                for (i2 = 0; i2 < length; i2 += 1) {
-                  partial[i2] = str(i2, value) || "null";
-                }
-                v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
-                gap = mind;
-                return v;
+              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;
               }
-              if (rep && typeof rep === "object") {
-                length = rep.length;
-                for (i2 = 0; i2 < length; i2 += 1) {
-                  if (typeof rep[i2] === "string") {
-                    k = rep[i2];
-                    v = str(k, value);
-                    if (v) {
-                      partial.push(quote(k) + (gap ? ": " : ":") + v);
-                    }
-                  }
-                }
-              } else {
-                for (k in value) {
-                  if (Object.prototype.hasOwnProperty.call(value, k)) {
-                    v = str(k, value);
-                    if (v) {
-                      partial.push(quote(k) + (gap ? ": " : ":") + v);
-                    }
-                  }
+              var comparator = this._comparator;
+              var t2 = splay(key, this._root, comparator);
+              var cmp2 = comparator(key, t2.key);
+              if (cmp2 === 0) this._root = t2;
+              else {
+                if (cmp2 < 0) {
+                  node.left = t2.left;
+                  node.right = t2;
+                  t2.left = null;
+                } else if (cmp2 > 0) {
+                  node.right = t2.right;
+                  node.left = t2;
+                  t2.right = null;
                 }
+                this._size++;
+                this._root = node;
               }
-              v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
-              gap = mind;
-              return v;
-          }
-        }
-        if (typeof JSON.stringify !== "function") {
-          meta = {
-            "\b": "\\b",
-            "  ": "\\t",
-            "\n": "\\n",
-            "\f": "\\f",
-            "\r": "\\r",
-            '"': '\\"',
-            "\\": "\\\\"
-          };
-          JSON.stringify = function(value, replacer, space) {
-            var i2;
-            gap = "";
-            indent = "";
-            if (typeof space === "number") {
-              for (i2 = 0; i2 < space; i2 += 1) {
-                indent += " ";
-              }
-            } else if (typeof space === "string") {
-              indent = space;
-            }
-            rep = replacer;
-            if (replacer && typeof replacer !== "function" && (typeof replacer !== "object" || typeof replacer.length !== "number")) {
-              throw new Error("JSON.stringify");
+              return this._root;
+            };
+            Tree2.prototype.remove = function(key) {
+              this._root = this._remove(key, this._root, this._comparator);
+            };
+            Tree2.prototype._remove = function(i3, t2, comparator) {
+              var x2;
+              if (t2 === null) return null;
+              t2 = splay(i3, t2, comparator);
+              var cmp2 = comparator(i3, t2.key);
+              if (cmp2 === 0) {
+                if (t2.left === null) {
+                  x2 = t2.right;
+                } else {
+                  x2 = splay(i3, t2.left, comparator);
+                  x2.right = t2.right;
+                }
+                this._size--;
+                return x2;
+              }
+              return t2;
+            };
+            Tree2.prototype.pop = function() {
+              var node = this._root;
+              if (node) {
+                while (node.left) node = node.left;
+                this._root = splay(node.key, this._root, this._comparator);
+                this._root = this._remove(node.key, this._root, this._comparator);
+                return {
+                  key: node.key,
+                  data: node.data
+                };
+              }
+              return null;
+            };
+            Tree2.prototype.findStatic = function(key) {
+              var current = this._root;
+              var compare2 = this._comparator;
+              while (current) {
+                var cmp2 = compare2(key, current.key);
+                if (cmp2 === 0) return current;
+                else if (cmp2 < 0) current = current.left;
+                else current = current.right;
+              }
+              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 this._root;
+            };
+            Tree2.prototype.contains = function(key) {
+              var current = this._root;
+              var compare2 = this._comparator;
+              while (current) {
+                var cmp2 = compare2(key, current.key);
+                if (cmp2 === 0) return true;
+                else if (cmp2 < 0) current = current.left;
+                else current = current.right;
+              }
+              return false;
+            };
+            Tree2.prototype.forEach = function(visitor, ctx) {
+              var current = this._root;
+              var Q2 = [];
+              var done = false;
+              while (!done) {
+                if (current !== null) {
+                  Q2.push(current);
+                  current = current.left;
+                } else {
+                  if (Q2.length !== 0) {
+                    current = Q2.pop();
+                    visitor.call(ctx, current);
+                    current = current.right;
+                  } else done = true;
+                }
+              }
+              return this;
+            };
+            Tree2.prototype.range = function(low, high, fn, ctx) {
+              var Q2 = [];
+              var compare2 = this._comparator;
+              var node = this._root;
+              var cmp2;
+              while (Q2.length !== 0 || node) {
+                if (node) {
+                  Q2.push(node);
+                  node = node.left;
+                } else {
+                  node = Q2.pop();
+                  cmp2 = compare2(node.key, high);
+                  if (cmp2 > 0) {
+                    break;
+                  } else if (compare2(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(_a3) {
+                var key = _a3.key;
+                return keys2.push(key);
+              });
+              return keys2;
+            };
+            Tree2.prototype.values = function() {
+              var values = [];
+              this.forEach(function(_a3) {
+                var data = _a3.data;
+                return values.push(data);
+              });
+              return values;
+            };
+            Tree2.prototype.min = function() {
+              if (this._root) return this.minNode(this._root).key;
+              return null;
+            };
+            Tree2.prototype.max = function() {
+              if (this._root) return this.maxNode(this._root).key;
+              return null;
+            };
+            Tree2.prototype.minNode = function(t2) {
+              if (t2 === void 0) {
+                t2 = this._root;
+              }
+              if (t2) while (t2.left) t2 = t2.left;
+              return t2;
+            };
+            Tree2.prototype.maxNode = function(t2) {
+              if (t2 === void 0) {
+                t2 = this._root;
+              }
+              if (t2) while (t2.right) t2 = t2.right;
+              return t2;
+            };
+            Tree2.prototype.at = function(index2) {
+              var current = this._root;
+              var done = false;
+              var i3 = 0;
+              var Q2 = [];
+              while (!done) {
+                if (current) {
+                  Q2.push(current);
+                  current = current.left;
+                } else {
+                  if (Q2.length > 0) {
+                    current = Q2.pop();
+                    if (i3 === index2) return current;
+                    i3++;
+                    current = current.right;
+                  } else done = true;
+                }
+              }
+              return null;
+            };
+            Tree2.prototype.next = function(d2) {
+              var root3 = this._root;
+              var successor = null;
+              if (d2.right) {
+                successor = d2.right;
+                while (successor.left) successor = successor.left;
+                return successor;
+              }
+              var comparator = this._comparator;
+              while (root3) {
+                var cmp2 = comparator(d2.key, root3.key);
+                if (cmp2 === 0) break;
+                else if (cmp2 < 0) {
+                  successor = root3;
+                  root3 = root3.left;
+                } else root3 = root3.right;
+              }
+              return successor;
+            };
+            Tree2.prototype.prev = function(d2) {
+              var root3 = this._root;
+              var predecessor = null;
+              if (d2.left !== null) {
+                predecessor = d2.left;
+                while (predecessor.right) predecessor = predecessor.right;
+                return predecessor;
+              }
+              var comparator = this._comparator;
+              while (root3) {
+                var cmp2 = comparator(d2.key, root3.key);
+                if (cmp2 === 0) break;
+                else if (cmp2 < 0) root3 = root3.left;
+                else {
+                  predecessor = root3;
+                  root3 = root3.right;
+                }
+              }
+              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(keys2, values, presort) {
+              if (values === void 0) {
+                values = [];
+              }
+              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() {
+                return this._size;
+              },
+              enumerable: true,
+              configurable: true
+            });
+            Object.defineProperty(Tree2.prototype, "root", {
+              get: function() {
+                return this._root;
+              },
+              enumerable: true,
+              configurable: true
+            });
+            Tree2.prototype.toString = function(printNode) {
+              if (printNode === void 0) {
+                printNode = function(n3) {
+                  return String(n3.key);
+                };
+              }
+              var out = [];
+              printRow(this._root, "", true, function(v2) {
+                return out.push(v2);
+              }, printNode);
+              return out.join("");
+            };
+            Tree2.prototype.update = function(key, newKey, newData) {
+              var comparator = this._comparator;
+              var _a3 = split(key, this._root, comparator), left = _a3.left, right = _a3.right;
+              if (comparator(key, newKey) < 0) {
+                right = insert(newKey, newData, right, comparator);
+              } else {
+                left = insert(newKey, newData, left, comparator);
+              }
+              this._root = merge2(left, right, comparator);
+            };
+            Tree2.prototype.split = function(key) {
+              return split(key, this._root, this._comparator);
+            };
+            Tree2.prototype[Symbol.iterator] = function() {
+              var current, Q2, done;
+              return __generator(this, function(_a3) {
+                switch (_a3.label) {
+                  case 0:
+                    current = this._root;
+                    Q2 = [];
+                    done = false;
+                    _a3.label = 1;
+                  case 1:
+                    if (!!done) return [3, 6];
+                    if (!(current !== null)) return [3, 2];
+                    Q2.push(current);
+                    current = current.left;
+                    return [3, 5];
+                  case 2:
+                    if (!(Q2.length !== 0)) return [3, 4];
+                    current = Q2.pop();
+                    return [4, current];
+                  case 3:
+                    _a3.sent();
+                    current = current.right;
+                    return [3, 5];
+                  case 4:
+                    done = true;
+                    _a3.label = 5;
+                  case 5:
+                    return [3, 1];
+                  case 6:
+                    return [
+                      2
+                      /*return*/
+                    ];
+                }
+              });
+            };
+            return Tree2;
+          }()
+        );
+        function loadRecursive(keys2, values, start2, end) {
+          var size = end - start2;
+          if (size > 0) {
+            var middle = start2 + Math.floor(size / 2);
+            var key = keys2[middle];
+            var data = values[middle];
+            var node = new Node(key, data);
+            node.left = loadRecursive(keys2, values, start2, middle);
+            node.right = loadRecursive(keys2, values, middle + 1, end);
+            return node;
+          }
+          return null;
+        }
+        function createList(keys2, values) {
+          var head = new Node(null, null);
+          var p2 = head;
+          for (var i3 = 0; i3 < keys2.length; i3++) {
+            p2 = p2.next = new Node(keys2[i3], values[i3]);
+          }
+          p2.next = null;
+          return head.next;
+        }
+        function toList(root3) {
+          var current = root3;
+          var Q2 = [];
+          var done = false;
+          var head = new Node(null, null);
+          var p2 = head;
+          while (!done) {
+            if (current) {
+              Q2.push(current);
+              current = current.left;
+            } else {
+              if (Q2.length > 0) {
+                current = p2 = p2.next = Q2.pop();
+                current = current.right;
+              } else done = true;
+            }
+          }
+          p2.next = null;
+          return head.next;
+        }
+        function sortedListToBST(list2, start2, end) {
+          var size = end - start2;
+          if (size > 0) {
+            var middle = start2 + Math.floor(size / 2);
+            var left = sortedListToBST(list2, start2, middle);
+            var root3 = list2.head;
+            root3.left = left;
+            list2.head = list2.head.next;
+            root3.right = sortedListToBST(list2, middle + 1, end);
+            return root3;
+          }
+          return null;
+        }
+        function mergeLists(l1, l2, compare2) {
+          var head = new Node(null, null);
+          var p2 = head;
+          var p1 = l1;
+          var p22 = l2;
+          while (p1 !== null && p22 !== null) {
+            if (compare2(p1.key, p22.key) < 0) {
+              p2.next = p1;
+              p1 = p1.next;
+            } else {
+              p2.next = p22;
+              p22 = p22.next;
+            }
+            p2 = p2.next;
+          }
+          if (p1 !== null) {
+            p2.next = p1;
+          } else if (p22 !== null) {
+            p2.next = p22;
+          }
+          return head.next;
+        }
+        function sort(keys2, values, left, right, compare2) {
+          if (left >= right) return;
+          var pivot = keys2[left + right >> 1];
+          var i3 = left - 1;
+          var j2 = right + 1;
+          while (true) {
+            do
+              i3++;
+            while (compare2(keys2[i3], pivot) < 0);
+            do
+              j2--;
+            while (compare2(keys2[j2], pivot) > 0);
+            if (i3 >= j2) break;
+            var tmp = keys2[i3];
+            keys2[i3] = keys2[j2];
+            keys2[j2] = tmp;
+            tmp = values[i3];
+            values[i3] = values[j2];
+            values[j2] = tmp;
+          }
+          sort(keys2, values, left, j2, compare2);
+          sort(keys2, values, j2 + 1, right, compare2);
+        }
+        const isInBbox2 = (bbox2, point) => {
+          return bbox2.ll.x <= point.x && point.x <= bbox2.ur.x && bbox2.ll.y <= point.y && point.y <= bbox2.ur.y;
+        };
+        const getBboxOverlap2 = (b1, b2) => {
+          if (b2.ur.x < b1.ll.x || b1.ur.x < b2.ll.x || b2.ur.y < b1.ll.y || b1.ur.y < b2.ll.y) return null;
+          const lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
+          const upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x;
+          const lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
+          const upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y;
+          return {
+            ll: {
+              x: lowerX,
+              y: lowerY
+            },
+            ur: {
+              x: upperX,
+              y: upperY
             }
-            return str("", { "": value });
           };
+        };
+        let epsilon$1 = Number.EPSILON;
+        if (epsilon$1 === void 0) epsilon$1 = Math.pow(2, -52);
+        const EPSILON_SQ = epsilon$1 * epsilon$1;
+        const cmp = (a2, b2) => {
+          if (-epsilon$1 < a2 && a2 < epsilon$1) {
+            if (-epsilon$1 < b2 && b2 < epsilon$1) {
+              return 0;
+            }
+          }
+          const ab = a2 - b2;
+          if (ab * ab < EPSILON_SQ * a2 * b2) {
+            return 0;
+          }
+          return a2 < b2 ? -1 : 1;
+        };
+        class PtRounder {
+          constructor() {
+            this.reset();
+          }
+          reset() {
+            this.xRounder = new CoordRounder();
+            this.yRounder = new CoordRounder();
+          }
+          round(x2, y2) {
+            return {
+              x: this.xRounder.round(x2),
+              y: this.yRounder.round(y2)
+            };
+          }
         }
-        if (typeof JSON.parse !== "function") {
-          JSON.parse = function(text, reviver) {
-            var j;
-            function walk(holder, key) {
-              var k;
-              var v;
-              var value = holder[key];
-              if (value && typeof value === "object") {
-                for (k in value) {
-                  if (Object.prototype.hasOwnProperty.call(value, k)) {
-                    v = walk(value, k);
-                    if (v !== void 0) {
-                      value[k] = v;
-                    } else {
-                      delete value[k];
+        class CoordRounder {
+          constructor() {
+            this.tree = new Tree();
+            this.round(0);
+          }
+          // Note: this can rounds input values backwards or forwards.
+          //       You might ask, why not restrict this to just rounding
+          //       forwards? Wouldn't that allow left endpoints to always
+          //       remain left endpoints during splitting (never change to
+          //       right). No - it wouldn't, because we snap intersections
+          //       to endpoints (to establish independence from the segment
+          //       angle for t-intersections).
+          round(coord2) {
+            const node = this.tree.add(coord2);
+            const prevNode = this.tree.prev(node);
+            if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
+              this.tree.remove(coord2);
+              return prevNode.key;
+            }
+            const nextNode = this.tree.next(node);
+            if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
+              this.tree.remove(coord2);
+              return nextNode.key;
+            }
+            return coord2;
+          }
+        }
+        const rounder = new PtRounder();
+        const epsilon3 = 11102230246251565e-32;
+        const splitter = 134217729;
+        const resulterrbound = (3 + 8 * epsilon3) * epsilon3;
+        function sum(elen, e3, flen, f2, h2) {
+          let Q2, Qnew, hh, bvirt;
+          let enow = e3[0];
+          let fnow = f2[0];
+          let eindex = 0;
+          let findex = 0;
+          if (fnow > enow === fnow > -enow) {
+            Q2 = enow;
+            enow = e3[++eindex];
+          } else {
+            Q2 = fnow;
+            fnow = f2[++findex];
+          }
+          let hindex = 0;
+          if (eindex < elen && findex < flen) {
+            if (fnow > enow === fnow > -enow) {
+              Qnew = enow + Q2;
+              hh = Q2 - (Qnew - enow);
+              enow = e3[++eindex];
+            } else {
+              Qnew = fnow + Q2;
+              hh = Q2 - (Qnew - fnow);
+              fnow = f2[++findex];
+            }
+            Q2 = Qnew;
+            if (hh !== 0) {
+              h2[hindex++] = hh;
+            }
+            while (eindex < elen && findex < flen) {
+              if (fnow > enow === fnow > -enow) {
+                Qnew = Q2 + enow;
+                bvirt = Qnew - Q2;
+                hh = Q2 - (Qnew - bvirt) + (enow - bvirt);
+                enow = e3[++eindex];
+              } else {
+                Qnew = Q2 + fnow;
+                bvirt = Qnew - Q2;
+                hh = Q2 - (Qnew - bvirt) + (fnow - bvirt);
+                fnow = f2[++findex];
+              }
+              Q2 = Qnew;
+              if (hh !== 0) {
+                h2[hindex++] = hh;
+              }
+            }
+          }
+          while (eindex < elen) {
+            Qnew = Q2 + enow;
+            bvirt = Qnew - Q2;
+            hh = Q2 - (Qnew - bvirt) + (enow - bvirt);
+            enow = e3[++eindex];
+            Q2 = Qnew;
+            if (hh !== 0) {
+              h2[hindex++] = hh;
+            }
+          }
+          while (findex < flen) {
+            Qnew = Q2 + fnow;
+            bvirt = Qnew - Q2;
+            hh = Q2 - (Qnew - bvirt) + (fnow - bvirt);
+            fnow = f2[++findex];
+            Q2 = Qnew;
+            if (hh !== 0) {
+              h2[hindex++] = hh;
+            }
+          }
+          if (Q2 !== 0 || hindex === 0) {
+            h2[hindex++] = Q2;
+          }
+          return hindex;
+        }
+        function estimate(elen, e3) {
+          let Q2 = e3[0];
+          for (let i3 = 1; i3 < elen; i3++) Q2 += e3[i3];
+          return Q2;
+        }
+        function vec(n3) {
+          return new Float64Array(n3);
+        }
+        const ccwerrboundA = (3 + 16 * epsilon3) * epsilon3;
+        const ccwerrboundB = (2 + 12 * epsilon3) * epsilon3;
+        const ccwerrboundC = (9 + 64 * epsilon3) * epsilon3 * epsilon3;
+        const B2 = vec(4);
+        const C1 = vec(8);
+        const C2 = vec(12);
+        const D2 = vec(16);
+        const u2 = vec(4);
+        function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
+          let acxtail, acytail, bcxtail, bcytail;
+          let bvirt, c2, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
+          const acx = ax - cx;
+          const bcx = bx - cx;
+          const acy = ay - cy;
+          const bcy = by - cy;
+          s1 = acx * bcy;
+          c2 = splitter * acx;
+          ahi = c2 - (c2 - acx);
+          alo = acx - ahi;
+          c2 = splitter * bcy;
+          bhi = c2 - (c2 - bcy);
+          blo = bcy - bhi;
+          s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+          t1 = acy * bcx;
+          c2 = splitter * acy;
+          ahi = c2 - (c2 - acy);
+          alo = acy - ahi;
+          c2 = splitter * bcx;
+          bhi = c2 - (c2 - bcx);
+          blo = bcx - bhi;
+          t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+          _i = s0 - t0;
+          bvirt = s0 - _i;
+          B2[0] = s0 - (_i + bvirt) + (bvirt - t0);
+          _j = s1 + _i;
+          bvirt = _j - s1;
+          _0 = s1 - (_j - bvirt) + (_i - bvirt);
+          _i = _0 - t1;
+          bvirt = _0 - _i;
+          B2[1] = _0 - (_i + bvirt) + (bvirt - t1);
+          u3 = _j + _i;
+          bvirt = u3 - _j;
+          B2[2] = _j - (u3 - bvirt) + (_i - bvirt);
+          B2[3] = u3;
+          let det = estimate(4, B2);
+          let errbound = ccwerrboundB * detsum;
+          if (det >= errbound || -det >= errbound) {
+            return det;
+          }
+          bvirt = ax - acx;
+          acxtail = ax - (acx + bvirt) + (bvirt - cx);
+          bvirt = bx - bcx;
+          bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
+          bvirt = ay - acy;
+          acytail = ay - (acy + bvirt) + (bvirt - cy);
+          bvirt = by - bcy;
+          bcytail = by - (bcy + bvirt) + (bvirt - cy);
+          if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
+            return det;
+          }
+          errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
+          det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
+          if (det >= errbound || -det >= errbound) return det;
+          s1 = acxtail * bcy;
+          c2 = splitter * acxtail;
+          ahi = c2 - (c2 - acxtail);
+          alo = acxtail - ahi;
+          c2 = splitter * bcy;
+          bhi = c2 - (c2 - bcy);
+          blo = bcy - bhi;
+          s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+          t1 = acytail * bcx;
+          c2 = splitter * acytail;
+          ahi = c2 - (c2 - acytail);
+          alo = acytail - ahi;
+          c2 = splitter * bcx;
+          bhi = c2 - (c2 - bcx);
+          blo = bcx - bhi;
+          t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+          _i = s0 - t0;
+          bvirt = s0 - _i;
+          u2[0] = s0 - (_i + bvirt) + (bvirt - t0);
+          _j = s1 + _i;
+          bvirt = _j - s1;
+          _0 = s1 - (_j - bvirt) + (_i - bvirt);
+          _i = _0 - t1;
+          bvirt = _0 - _i;
+          u2[1] = _0 - (_i + bvirt) + (bvirt - t1);
+          u3 = _j + _i;
+          bvirt = u3 - _j;
+          u2[2] = _j - (u3 - bvirt) + (_i - bvirt);
+          u2[3] = u3;
+          const C1len = sum(4, B2, 4, u2, C1);
+          s1 = acx * bcytail;
+          c2 = splitter * acx;
+          ahi = c2 - (c2 - acx);
+          alo = acx - ahi;
+          c2 = splitter * bcytail;
+          bhi = c2 - (c2 - bcytail);
+          blo = bcytail - bhi;
+          s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+          t1 = acy * bcxtail;
+          c2 = splitter * acy;
+          ahi = c2 - (c2 - acy);
+          alo = acy - ahi;
+          c2 = splitter * bcxtail;
+          bhi = c2 - (c2 - bcxtail);
+          blo = bcxtail - bhi;
+          t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+          _i = s0 - t0;
+          bvirt = s0 - _i;
+          u2[0] = s0 - (_i + bvirt) + (bvirt - t0);
+          _j = s1 + _i;
+          bvirt = _j - s1;
+          _0 = s1 - (_j - bvirt) + (_i - bvirt);
+          _i = _0 - t1;
+          bvirt = _0 - _i;
+          u2[1] = _0 - (_i + bvirt) + (bvirt - t1);
+          u3 = _j + _i;
+          bvirt = u3 - _j;
+          u2[2] = _j - (u3 - bvirt) + (_i - bvirt);
+          u2[3] = u3;
+          const C2len = sum(C1len, C1, 4, u2, C2);
+          s1 = acxtail * bcytail;
+          c2 = splitter * acxtail;
+          ahi = c2 - (c2 - acxtail);
+          alo = acxtail - ahi;
+          c2 = splitter * bcytail;
+          bhi = c2 - (c2 - bcytail);
+          blo = bcytail - bhi;
+          s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+          t1 = acytail * bcxtail;
+          c2 = splitter * acytail;
+          ahi = c2 - (c2 - acytail);
+          alo = acytail - ahi;
+          c2 = splitter * bcxtail;
+          bhi = c2 - (c2 - bcxtail);
+          blo = bcxtail - bhi;
+          t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+          _i = s0 - t0;
+          bvirt = s0 - _i;
+          u2[0] = s0 - (_i + bvirt) + (bvirt - t0);
+          _j = s1 + _i;
+          bvirt = _j - s1;
+          _0 = s1 - (_j - bvirt) + (_i - bvirt);
+          _i = _0 - t1;
+          bvirt = _0 - _i;
+          u2[1] = _0 - (_i + bvirt) + (bvirt - t1);
+          u3 = _j + _i;
+          bvirt = u3 - _j;
+          u2[2] = _j - (u3 - bvirt) + (_i - bvirt);
+          u2[3] = u3;
+          const Dlen = sum(C2len, C2, 4, u2, D2);
+          return D2[Dlen - 1];
+        }
+        function orient2d(ax, ay, bx, by, cx, cy) {
+          const detleft = (ay - cy) * (bx - cx);
+          const detright = (ax - cx) * (by - cy);
+          const det = detleft - detright;
+          const detsum = Math.abs(detleft + detright);
+          if (Math.abs(det) >= ccwerrboundA * detsum) return det;
+          return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
+        }
+        const crossProduct2 = (a2, b2) => a2.x * b2.y - a2.y * b2.x;
+        const dotProduct2 = (a2, b2) => a2.x * b2.x + a2.y * b2.y;
+        const compareVectorAngles = (basePt, endPt1, endPt2) => {
+          const res = orient2d(basePt.x, basePt.y, endPt1.x, endPt1.y, endPt2.x, endPt2.y);
+          if (res > 0) return -1;
+          if (res < 0) return 1;
+          return 0;
+        };
+        const length2 = (v2) => Math.sqrt(dotProduct2(v2, v2));
+        const sineOfAngle2 = (pShared, pBase, pAngle) => {
+          const vBase = {
+            x: pBase.x - pShared.x,
+            y: pBase.y - pShared.y
+          };
+          const vAngle = {
+            x: pAngle.x - pShared.x,
+            y: pAngle.y - pShared.y
+          };
+          return crossProduct2(vAngle, vBase) / length2(vAngle) / length2(vBase);
+        };
+        const cosineOfAngle2 = (pShared, pBase, pAngle) => {
+          const vBase = {
+            x: pBase.x - pShared.x,
+            y: pBase.y - pShared.y
+          };
+          const vAngle = {
+            x: pAngle.x - pShared.x,
+            y: pAngle.y - pShared.y
+          };
+          return dotProduct2(vAngle, vBase) / length2(vAngle) / length2(vBase);
+        };
+        const horizontalIntersection2 = (pt2, v2, y2) => {
+          if (v2.y === 0) return null;
+          return {
+            x: pt2.x + v2.x / v2.y * (y2 - pt2.y),
+            y: y2
+          };
+        };
+        const verticalIntersection2 = (pt2, v2, x2) => {
+          if (v2.x === 0) return null;
+          return {
+            x: x2,
+            y: pt2.y + v2.y / v2.x * (x2 - pt2.x)
+          };
+        };
+        const intersection$1 = (pt1, v1, pt2, v2) => {
+          if (v1.x === 0) return verticalIntersection2(pt2, v2, pt1.x);
+          if (v2.x === 0) return verticalIntersection2(pt1, v1, pt2.x);
+          if (v1.y === 0) return horizontalIntersection2(pt2, v2, pt1.y);
+          if (v2.y === 0) return horizontalIntersection2(pt1, v1, pt2.y);
+          const kross = crossProduct2(v1, v2);
+          if (kross == 0) return null;
+          const ve2 = {
+            x: pt2.x - pt1.x,
+            y: pt2.y - pt1.y
+          };
+          const d1 = crossProduct2(ve2, v1) / kross;
+          const d2 = crossProduct2(ve2, v2) / kross;
+          const x12 = pt1.x + d2 * v1.x, x2 = pt2.x + d1 * v2.x;
+          const y12 = pt1.y + d2 * v1.y, y2 = pt2.y + d1 * v2.y;
+          const x3 = (x12 + x2) / 2;
+          const y3 = (y12 + y2) / 2;
+          return {
+            x: x3,
+            y: y3
+          };
+        };
+        class SweepEvent2 {
+          // for ordering sweep events in the sweep event queue
+          static compare(a2, b2) {
+            const ptCmp = SweepEvent2.comparePoints(a2.point, b2.point);
+            if (ptCmp !== 0) return ptCmp;
+            if (a2.point !== b2.point) a2.link(b2);
+            if (a2.isLeft !== b2.isLeft) return a2.isLeft ? 1 : -1;
+            return Segment2.compare(a2.segment, b2.segment);
+          }
+          // for ordering points in sweep line order
+          static comparePoints(aPt, bPt) {
+            if (aPt.x < bPt.x) return -1;
+            if (aPt.x > bPt.x) return 1;
+            if (aPt.y < bPt.y) return -1;
+            if (aPt.y > bPt.y) return 1;
+            return 0;
+          }
+          // Warning: 'point' input will be modified and re-used (for performance)
+          constructor(point, isLeft) {
+            if (point.events === void 0) point.events = [this];
+            else point.events.push(this);
+            this.point = point;
+            this.isLeft = isLeft;
+          }
+          link(other) {
+            if (other.point === this.point) {
+              throw new Error("Tried to link already linked events");
+            }
+            const otherEvents = other.point.events;
+            for (let i3 = 0, iMax = otherEvents.length; i3 < iMax; i3++) {
+              const evt = otherEvents[i3];
+              this.point.events.push(evt);
+              evt.point = this.point;
+            }
+            this.checkForConsuming();
+          }
+          /* Do a pass over our linked events and check to see if any pair
+           * of segments match, and should be consumed. */
+          checkForConsuming() {
+            const numEvents = this.point.events.length;
+            for (let i3 = 0; i3 < numEvents; i3++) {
+              const evt1 = this.point.events[i3];
+              if (evt1.segment.consumedBy !== void 0) continue;
+              for (let j2 = i3 + 1; j2 < numEvents; j2++) {
+                const evt2 = this.point.events[j2];
+                if (evt2.consumedBy !== void 0) continue;
+                if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
+                evt1.segment.consume(evt2.segment);
+              }
+            }
+          }
+          getAvailableLinkedEvents() {
+            const events = [];
+            for (let i3 = 0, iMax = this.point.events.length; i3 < iMax; i3++) {
+              const evt = this.point.events[i3];
+              if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
+                events.push(evt);
+              }
+            }
+            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.
+           */
+          getLeftmostComparator(baseEvent) {
+            const cache = /* @__PURE__ */ new Map();
+            const fillCache = (linkedEvent) => {
+              const nextEvent = linkedEvent.otherSE;
+              cache.set(linkedEvent, {
+                sine: sineOfAngle2(this.point, baseEvent.point, nextEvent.point),
+                cosine: cosineOfAngle2(this.point, baseEvent.point, nextEvent.point)
+              });
+            };
+            return (a2, b2) => {
+              if (!cache.has(a2)) fillCache(a2);
+              if (!cache.has(b2)) fillCache(b2);
+              const {
+                sine: asine,
+                cosine: acosine
+              } = cache.get(a2);
+              const {
+                sine: bsine,
+                cosine: bcosine
+              } = cache.get(b2);
+              if (asine >= 0 && bsine >= 0) {
+                if (acosine < bcosine) return 1;
+                if (acosine > bcosine) return -1;
+                return 0;
+              }
+              if (asine < 0 && bsine < 0) {
+                if (acosine < bcosine) return -1;
+                if (acosine > bcosine) return 1;
+                return 0;
+              }
+              if (bsine < asine) return -1;
+              if (bsine > asine) return 1;
+              return 0;
+            };
+          }
+        }
+        let segmentId2 = 0;
+        class Segment2 {
+          /* 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.
+           */
+          static compare(a2, b2) {
+            const alx = a2.leftSE.point.x;
+            const blx = b2.leftSE.point.x;
+            const arx = a2.rightSE.point.x;
+            const brx = b2.rightSE.point.x;
+            if (brx < alx) return 1;
+            if (arx < blx) return -1;
+            const aly = a2.leftSE.point.y;
+            const bly = b2.leftSE.point.y;
+            const ary = a2.rightSE.point.y;
+            const bry = b2.rightSE.point.y;
+            if (alx < blx) {
+              if (bly < aly && bly < ary) return 1;
+              if (bly > aly && bly > ary) return -1;
+              const aCmpBLeft = a2.comparePoint(b2.leftSE.point);
+              if (aCmpBLeft < 0) return 1;
+              if (aCmpBLeft > 0) return -1;
+              const bCmpARight = b2.comparePoint(a2.rightSE.point);
+              if (bCmpARight !== 0) return bCmpARight;
+              return -1;
+            }
+            if (alx > blx) {
+              if (aly < bly && aly < bry) return -1;
+              if (aly > bly && aly > bry) return 1;
+              const bCmpALeft = b2.comparePoint(a2.leftSE.point);
+              if (bCmpALeft !== 0) return bCmpALeft;
+              const aCmpBRight = a2.comparePoint(b2.rightSE.point);
+              if (aCmpBRight < 0) return 1;
+              if (aCmpBRight > 0) return -1;
+              return 1;
+            }
+            if (aly < bly) return -1;
+            if (aly > bly) return 1;
+            if (arx < brx) {
+              const bCmpARight = b2.comparePoint(a2.rightSE.point);
+              if (bCmpARight !== 0) return bCmpARight;
+            }
+            if (arx > brx) {
+              const aCmpBRight = a2.comparePoint(b2.rightSE.point);
+              if (aCmpBRight < 0) return 1;
+              if (aCmpBRight > 0) return -1;
+            }
+            if (arx !== brx) {
+              const ay = ary - aly;
+              const ax = arx - alx;
+              const by = bry - bly;
+              const bx = brx - blx;
+              if (ay > ax && by < bx) return 1;
+              if (ay < ax && by > bx) return -1;
+            }
+            if (arx > brx) return 1;
+            if (arx < brx) return -1;
+            if (ary < bry) return -1;
+            if (ary > bry) return 1;
+            if (a2.id < b2.id) return -1;
+            if (a2.id > b2.id) return 1;
+            return 0;
+          }
+          /* Warning: a reference to ringWindings input will be stored,
+           *  and possibly will be later modified */
+          constructor(leftSE, rightSE, rings, windings) {
+            this.id = ++segmentId2;
+            this.leftSE = leftSE;
+            leftSE.segment = this;
+            leftSE.otherSE = rightSE;
+            this.rightSE = rightSE;
+            rightSE.segment = this;
+            rightSE.otherSE = leftSE;
+            this.rings = rings;
+            this.windings = windings;
+          }
+          static fromRing(pt1, pt2, ring) {
+            let leftPt, rightPt, winding;
+            const cmpPts = SweepEvent2.comparePoints(pt1, pt2);
+            if (cmpPts < 0) {
+              leftPt = pt1;
+              rightPt = pt2;
+              winding = 1;
+            } else if (cmpPts > 0) {
+              leftPt = pt2;
+              rightPt = pt1;
+              winding = -1;
+            } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
+            const leftSE = new SweepEvent2(leftPt, true);
+            const rightSE = new SweepEvent2(rightPt, false);
+            return new Segment2(leftSE, rightSE, [ring], [winding]);
+          }
+          /* When a segment is split, the rightSE is replaced with a new sweep event */
+          replaceRightSE(newRightSE) {
+            this.rightSE = newRightSE;
+            this.rightSE.segment = this;
+            this.rightSE.otherSE = this.leftSE;
+            this.leftSE.otherSE = this.rightSE;
+          }
+          bbox() {
+            const y12 = this.leftSE.point.y;
+            const y2 = this.rightSE.point.y;
+            return {
+              ll: {
+                x: this.leftSE.point.x,
+                y: y12 < y2 ? y12 : y2
+              },
+              ur: {
+                x: this.rightSE.point.x,
+                y: y12 > y2 ? y12 : y2
+              }
+            };
+          }
+          /* A vector from the left point to the right */
+          vector() {
+            return {
+              x: this.rightSE.point.x - this.leftSE.point.x,
+              y: this.rightSE.point.y - this.leftSE.point.y
+            };
+          }
+          isAnEndpoint(pt2) {
+            return pt2.x === this.leftSE.point.x && pt2.y === this.leftSE.point.y || pt2.x === this.rightSE.point.x && pt2.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)
+           */
+          comparePoint(point) {
+            if (this.isAnEndpoint(point)) return 0;
+            const lPt = this.leftSE.point;
+            const rPt = this.rightSE.point;
+            const v2 = this.vector();
+            if (lPt.x === rPt.x) {
+              if (point.x === lPt.x) return 0;
+              return point.x < lPt.x ? 1 : -1;
+            }
+            const yDist = (point.y - lPt.y) / v2.y;
+            const xFromYDist = lPt.x + yDist * v2.x;
+            if (point.x === xFromYDist) return 0;
+            const xDist = (point.x - lPt.x) / v2.x;
+            const yFromXDist = lPt.y + xDist * v2.y;
+            if (point.y === yFromXDist) return 0;
+            return point.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.
+           */
+          getIntersection(other) {
+            const tBbox = this.bbox();
+            const oBbox = other.bbox();
+            const bboxOverlap = getBboxOverlap2(tBbox, oBbox);
+            if (bboxOverlap === null) return null;
+            const tlp = this.leftSE.point;
+            const trp = this.rightSE.point;
+            const olp = other.leftSE.point;
+            const orp = other.rightSE.point;
+            const touchesOtherLSE = isInBbox2(tBbox, olp) && this.comparePoint(olp) === 0;
+            const touchesThisLSE = isInBbox2(oBbox, tlp) && other.comparePoint(tlp) === 0;
+            const touchesOtherRSE = isInBbox2(tBbox, orp) && this.comparePoint(orp) === 0;
+            const touchesThisRSE = isInBbox2(oBbox, trp) && other.comparePoint(trp) === 0;
+            if (touchesThisLSE && touchesOtherLSE) {
+              if (touchesThisRSE && !touchesOtherRSE) return trp;
+              if (!touchesThisRSE && touchesOtherRSE) return orp;
+              return null;
+            }
+            if (touchesThisLSE) {
+              if (touchesOtherRSE) {
+                if (tlp.x === orp.x && tlp.y === orp.y) return null;
+              }
+              return tlp;
+            }
+            if (touchesOtherLSE) {
+              if (touchesThisRSE) {
+                if (trp.x === olp.x && trp.y === olp.y) return null;
+              }
+              return olp;
+            }
+            if (touchesThisRSE && touchesOtherRSE) return null;
+            if (touchesThisRSE) return trp;
+            if (touchesOtherRSE) return orp;
+            const pt2 = intersection$1(tlp, this.vector(), olp, other.vector());
+            if (pt2 === null) return null;
+            if (!isInBbox2(bboxOverlap, pt2)) return null;
+            return rounder.round(pt2.x, pt2.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
+           */
+          split(point) {
+            const newEvents = [];
+            const alreadyLinked = point.events !== void 0;
+            const newLeftSE = new SweepEvent2(point, true);
+            const newRightSE = new SweepEvent2(point, false);
+            const oldRightSE = this.rightSE;
+            this.replaceRightSE(newRightSE);
+            newEvents.push(newRightSE);
+            newEvents.push(newLeftSE);
+            const newSeg = new Segment2(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice());
+            if (SweepEvent2.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
+              newSeg.swapEvents();
+            }
+            if (SweepEvent2.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
+              this.swapEvents();
+            }
+            if (alreadyLinked) {
+              newLeftSE.checkForConsuming();
+              newRightSE.checkForConsuming();
+            }
+            return newEvents;
+          }
+          /* Swap which event is left and right */
+          swapEvents() {
+            const tmpEvt = this.rightSE;
+            this.rightSE = this.leftSE;
+            this.leftSE = tmpEvt;
+            this.leftSE.isLeft = true;
+            this.rightSE.isLeft = false;
+            for (let i3 = 0, iMax = this.windings.length; i3 < iMax; i3++) {
+              this.windings[i3] *= -1;
+            }
+          }
+          /* Consume another segment. We take their rings under our wing
+           * and mark them as consumed. Use for perfectly overlapping segments */
+          consume(other) {
+            let consumer = this;
+            let consumee = other;
+            while (consumer.consumedBy) consumer = consumer.consumedBy;
+            while (consumee.consumedBy) consumee = consumee.consumedBy;
+            const cmp2 = Segment2.compare(consumer, consumee);
+            if (cmp2 === 0) return;
+            if (cmp2 > 0) {
+              const tmp = consumer;
+              consumer = consumee;
+              consumee = tmp;
+            }
+            if (consumer.prev === consumee) {
+              const tmp = consumer;
+              consumer = consumee;
+              consumee = tmp;
+            }
+            for (let i3 = 0, iMax = consumee.rings.length; i3 < iMax; i3++) {
+              const ring = consumee.rings[i3];
+              const winding = consumee.windings[i3];
+              const index2 = consumer.rings.indexOf(ring);
+              if (index2 === -1) {
+                consumer.rings.push(ring);
+                consumer.windings.push(winding);
+              } else consumer.windings[index2] += winding;
+            }
+            consumee.rings = null;
+            consumee.windings = null;
+            consumee.consumedBy = consumer;
+            consumee.leftSE.consumedBy = consumer.leftSE;
+            consumee.rightSE.consumedBy = consumer.rightSE;
+          }
+          /* The first segment previous segment chain that is in the result */
+          prevInResult() {
+            if (this._prevInResult !== void 0) return this._prevInResult;
+            if (!this.prev) this._prevInResult = null;
+            else if (this.prev.isInResult()) this._prevInResult = this.prev;
+            else this._prevInResult = this.prev.prevInResult();
+            return this._prevInResult;
+          }
+          beforeState() {
+            if (this._beforeState !== void 0) return this._beforeState;
+            if (!this.prev) this._beforeState = {
+              rings: [],
+              windings: [],
+              multiPolys: []
+            };
+            else {
+              const seg = this.prev.consumedBy || this.prev;
+              this._beforeState = seg.afterState();
+            }
+            return this._beforeState;
+          }
+          afterState() {
+            if (this._afterState !== void 0) return this._afterState;
+            const beforeState = this.beforeState();
+            this._afterState = {
+              rings: beforeState.rings.slice(0),
+              windings: beforeState.windings.slice(0),
+              multiPolys: []
+            };
+            const ringsAfter = this._afterState.rings;
+            const windingsAfter = this._afterState.windings;
+            const mpsAfter = this._afterState.multiPolys;
+            for (let i3 = 0, iMax = this.rings.length; i3 < iMax; i3++) {
+              const ring = this.rings[i3];
+              const winding = this.windings[i3];
+              const index2 = ringsAfter.indexOf(ring);
+              if (index2 === -1) {
+                ringsAfter.push(ring);
+                windingsAfter.push(winding);
+              } else windingsAfter[index2] += winding;
+            }
+            const polysAfter = [];
+            const polysExclude = [];
+            for (let i3 = 0, iMax = ringsAfter.length; i3 < iMax; i3++) {
+              if (windingsAfter[i3] === 0) continue;
+              const ring = ringsAfter[i3];
+              const poly = ring.poly;
+              if (polysExclude.indexOf(poly) !== -1) continue;
+              if (ring.isExterior) polysAfter.push(poly);
+              else {
+                if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
+                const index2 = polysAfter.indexOf(ring.poly);
+                if (index2 !== -1) polysAfter.splice(index2, 1);
+              }
+            }
+            for (let i3 = 0, iMax = polysAfter.length; i3 < iMax; i3++) {
+              const mp = polysAfter[i3].multiPoly;
+              if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
+            }
+            return this._afterState;
+          }
+          /* Is this segment part of the final result? */
+          isInResult() {
+            if (this.consumedBy) return false;
+            if (this._isInResult !== void 0) return this._isInResult;
+            const mpsBefore = this.beforeState().multiPolys;
+            const mpsAfter = this.afterState().multiPolys;
+            switch (operation2.type) {
+              case "union": {
+                const noBefores = mpsBefore.length === 0;
+                const noAfters = mpsAfter.length === 0;
+                this._isInResult = noBefores !== noAfters;
+                break;
+              }
+              case "intersection": {
+                let least;
+                let most;
+                if (mpsBefore.length < mpsAfter.length) {
+                  least = mpsBefore.length;
+                  most = mpsAfter.length;
+                } else {
+                  least = mpsAfter.length;
+                  most = mpsBefore.length;
+                }
+                this._isInResult = most === operation2.numMultiPolys && least < most;
+                break;
+              }
+              case "xor": {
+                const diff = Math.abs(mpsBefore.length - mpsAfter.length);
+                this._isInResult = diff % 2 === 1;
+                break;
+              }
+              case "difference": {
+                const isJustSubject = (mps) => mps.length === 1 && mps[0].isSubject;
+                this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
+                break;
+              }
+              default:
+                throw new Error("Unrecognized operation type found ".concat(operation2.type));
+            }
+            return this._isInResult;
+          }
+        }
+        class RingIn2 {
+          constructor(geomRing, poly, isExterior) {
+            if (!Array.isArray(geomRing) || geomRing.length === 0) {
+              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+            }
+            this.poly = poly;
+            this.isExterior = isExterior;
+            this.segments = [];
+            if (typeof geomRing[0][0] !== "number" || typeof geomRing[0][1] !== "number") {
+              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+            }
+            const firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
+            this.bbox = {
+              ll: {
+                x: firstPoint.x,
+                y: firstPoint.y
+              },
+              ur: {
+                x: firstPoint.x,
+                y: firstPoint.y
+              }
+            };
+            let prevPoint = firstPoint;
+            for (let i3 = 1, iMax = geomRing.length; i3 < iMax; i3++) {
+              if (typeof geomRing[i3][0] !== "number" || typeof geomRing[i3][1] !== "number") {
+                throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+              }
+              let point = rounder.round(geomRing[i3][0], geomRing[i3][1]);
+              if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
+              this.segments.push(Segment2.fromRing(prevPoint, point, this));
+              if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
+              if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
+              if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
+              if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
+              prevPoint = point;
+            }
+            if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
+              this.segments.push(Segment2.fromRing(prevPoint, firstPoint, this));
+            }
+          }
+          getSweepEvents() {
+            const sweepEvents = [];
+            for (let i3 = 0, iMax = this.segments.length; i3 < iMax; i3++) {
+              const segment = this.segments[i3];
+              sweepEvents.push(segment.leftSE);
+              sweepEvents.push(segment.rightSE);
+            }
+            return sweepEvents;
+          }
+        }
+        class PolyIn2 {
+          constructor(geomPoly, multiPoly) {
+            if (!Array.isArray(geomPoly)) {
+              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+            }
+            this.exteriorRing = new RingIn2(geomPoly[0], this, true);
+            this.bbox = {
+              ll: {
+                x: this.exteriorRing.bbox.ll.x,
+                y: this.exteriorRing.bbox.ll.y
+              },
+              ur: {
+                x: this.exteriorRing.bbox.ur.x,
+                y: this.exteriorRing.bbox.ur.y
+              }
+            };
+            this.interiorRings = [];
+            for (let i3 = 1, iMax = geomPoly.length; i3 < iMax; i3++) {
+              const ring = new RingIn2(geomPoly[i3], this, false);
+              if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
+              if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
+              if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
+              if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
+              this.interiorRings.push(ring);
+            }
+            this.multiPoly = multiPoly;
+          }
+          getSweepEvents() {
+            const sweepEvents = this.exteriorRing.getSweepEvents();
+            for (let i3 = 0, iMax = this.interiorRings.length; i3 < iMax; i3++) {
+              const ringSweepEvents = this.interiorRings[i3].getSweepEvents();
+              for (let j2 = 0, jMax = ringSweepEvents.length; j2 < jMax; j2++) {
+                sweepEvents.push(ringSweepEvents[j2]);
+              }
+            }
+            return sweepEvents;
+          }
+        }
+        class MultiPolyIn2 {
+          constructor(geom, isSubject) {
+            if (!Array.isArray(geom)) {
+              throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+            }
+            try {
+              if (typeof geom[0][0][0] === "number") geom = [geom];
+            } catch (ex) {
+            }
+            this.polys = [];
+            this.bbox = {
+              ll: {
+                x: Number.POSITIVE_INFINITY,
+                y: Number.POSITIVE_INFINITY
+              },
+              ur: {
+                x: Number.NEGATIVE_INFINITY,
+                y: Number.NEGATIVE_INFINITY
+              }
+            };
+            for (let i3 = 0, iMax = geom.length; i3 < iMax; i3++) {
+              const poly = new PolyIn2(geom[i3], this);
+              if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
+              if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
+              if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
+              if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
+              this.polys.push(poly);
+            }
+            this.isSubject = isSubject;
+          }
+          getSweepEvents() {
+            const sweepEvents = [];
+            for (let i3 = 0, iMax = this.polys.length; i3 < iMax; i3++) {
+              const polySweepEvents = this.polys[i3].getSweepEvents();
+              for (let j2 = 0, jMax = polySweepEvents.length; j2 < jMax; j2++) {
+                sweepEvents.push(polySweepEvents[j2]);
+              }
+            }
+            return sweepEvents;
+          }
+        }
+        class RingOut2 {
+          /* 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 */
+          static factory(allSegments) {
+            const ringsOut = [];
+            for (let i3 = 0, iMax = allSegments.length; i3 < iMax; i3++) {
+              const segment = allSegments[i3];
+              if (!segment.isInResult() || segment.ringOut) continue;
+              let prevEvent = null;
+              let event = segment.leftSE;
+              let nextEvent = segment.rightSE;
+              const events = [event];
+              const startingPoint = event.point;
+              const intersectionLEs = [];
+              while (true) {
+                prevEvent = event;
+                event = nextEvent;
+                events.push(event);
+                if (event.point === startingPoint) break;
+                while (true) {
+                  const availableLEs = event.getAvailableLinkedEvents();
+                  if (availableLEs.length === 0) {
+                    const firstPt = events[0].point;
+                    const lastPt = events[events.length - 1].point;
+                    throw new Error("Unable to complete output ring starting at [".concat(firstPt.x, ",") + " ".concat(firstPt.y, "]. Last matching segment found ends at") + " [".concat(lastPt.x, ", ").concat(lastPt.y, "]."));
+                  }
+                  if (availableLEs.length === 1) {
+                    nextEvent = availableLEs[0].otherSE;
+                    break;
+                  }
+                  let indexLE = null;
+                  for (let j2 = 0, jMax = intersectionLEs.length; j2 < jMax; j2++) {
+                    if (intersectionLEs[j2].point === event.point) {
+                      indexLE = j2;
+                      break;
                     }
                   }
+                  if (indexLE !== null) {
+                    const intersectionLE = intersectionLEs.splice(indexLE)[0];
+                    const ringEvents = events.splice(intersectionLE.index);
+                    ringEvents.unshift(ringEvents[0].otherSE);
+                    ringsOut.push(new RingOut2(ringEvents.reverse()));
+                    continue;
+                  }
+                  intersectionLEs.push({
+                    index: events.length,
+                    point: event.point
+                  });
+                  const comparator = event.getLeftmostComparator(prevEvent);
+                  nextEvent = availableLEs.sort(comparator)[0].otherSE;
+                  break;
                 }
               }
-              return reviver.call(holder, key, value);
+              ringsOut.push(new RingOut2(events));
             }
-            text = String(text);
-            rx_dangerous.lastIndex = 0;
-            if (rx_dangerous.test(text)) {
-              text = text.replace(rx_dangerous, function(a) {
-                return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
-              });
+            return ringsOut;
+          }
+          constructor(events) {
+            this.events = events;
+            for (let i3 = 0, iMax = events.length; i3 < iMax; i3++) {
+              events[i3].segment.ringOut = this;
             }
-            if (rx_one.test(
-              text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, "")
-            )) {
-              j = eval("(" + text + ")");
-              return typeof reviver === "function" ? walk({ "": j }, "") : j;
+            this.poly = null;
+          }
+          getGeom() {
+            let prevPt = this.events[0].point;
+            const points = [prevPt];
+            for (let i3 = 1, iMax = this.events.length - 1; i3 < iMax; i3++) {
+              const pt3 = this.events[i3].point;
+              const nextPt2 = this.events[i3 + 1].point;
+              if (compareVectorAngles(pt3, prevPt, nextPt2) === 0) continue;
+              points.push(pt3);
+              prevPt = pt3;
+            }
+            if (points.length === 1) return null;
+            const pt2 = points[0];
+            const nextPt = points[1];
+            if (compareVectorAngles(pt2, prevPt, nextPt) === 0) points.shift();
+            points.push(points[0]);
+            const step = this.isExteriorRing() ? 1 : -1;
+            const iStart = this.isExteriorRing() ? 0 : points.length - 1;
+            const iEnd = this.isExteriorRing() ? points.length : -1;
+            const orderedPoints = [];
+            for (let i3 = iStart; i3 != iEnd; i3 += step) orderedPoints.push([points[i3].x, points[i3].y]);
+            return orderedPoints;
+          }
+          isExteriorRing() {
+            if (this._isExteriorRing === void 0) {
+              const enclosing = this.enclosingRing();
+              this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
+            }
+            return this._isExteriorRing;
+          }
+          enclosingRing() {
+            if (this._enclosingRing === void 0) {
+              this._enclosingRing = this._calcEnclosingRing();
+            }
+            return this._enclosingRing;
+          }
+          /* Returns the ring that encloses this one, if any */
+          _calcEnclosingRing() {
+            let leftMostEvt = this.events[0];
+            for (let i3 = 1, iMax = this.events.length; i3 < iMax; i3++) {
+              const evt = this.events[i3];
+              if (SweepEvent2.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
+            }
+            let prevSeg = leftMostEvt.segment.prevInResult();
+            let prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
+            while (true) {
+              if (!prevSeg) return null;
+              if (!prevPrevSeg) return prevSeg.ringOut;
+              if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
+                if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
+                  return prevSeg.ringOut;
+                } else return prevSeg.ringOut.enclosingRing();
+              }
+              prevSeg = prevPrevSeg.prevInResult();
+              prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
             }
-            throw new SyntaxError("JSON.parse");
-          };
+          }
         }
-      })();
-    }
-  });
-
-  // node_modules/store/plugins/json2.js
-  var require_json22 = __commonJS({
-    "node_modules/store/plugins/json2.js"(exports2, module2) {
-      module2.exports = json2Plugin;
-      function json2Plugin() {
-        require_json2();
-        return {};
-      }
-    }
-  });
-
-  // node_modules/store/dist/store.legacy.js
-  var require_store_legacy = __commonJS({
-    "node_modules/store/dist/store.legacy.js"(exports2, module2) {
-      var engine = require_store_engine();
-      var storages = require_all();
-      var plugins = [require_json22()];
-      module2.exports = engine.createStore(storages, plugins);
+        class PolyOut2 {
+          constructor(exteriorRing) {
+            this.exteriorRing = exteriorRing;
+            exteriorRing.poly = this;
+            this.interiorRings = [];
+          }
+          addInterior(ring) {
+            this.interiorRings.push(ring);
+            ring.poly = this;
+          }
+          getGeom() {
+            const geom = [this.exteriorRing.getGeom()];
+            if (geom[0] === null) return null;
+            for (let i3 = 0, iMax = this.interiorRings.length; i3 < iMax; i3++) {
+              const ringGeom = this.interiorRings[i3].getGeom();
+              if (ringGeom === null) continue;
+              geom.push(ringGeom);
+            }
+            return geom;
+          }
+        }
+        class MultiPolyOut2 {
+          constructor(rings) {
+            this.rings = rings;
+            this.polys = this._composePolys(rings);
+          }
+          getGeom() {
+            const geom = [];
+            for (let i3 = 0, iMax = this.polys.length; i3 < iMax; i3++) {
+              const polyGeom = this.polys[i3].getGeom();
+              if (polyGeom === null) continue;
+              geom.push(polyGeom);
+            }
+            return geom;
+          }
+          _composePolys(rings) {
+            const polys = [];
+            for (let i3 = 0, iMax = rings.length; i3 < iMax; i3++) {
+              const ring = rings[i3];
+              if (ring.poly) continue;
+              if (ring.isExteriorRing()) polys.push(new PolyOut2(ring));
+              else {
+                const enclosingRing = ring.enclosingRing();
+                if (!enclosingRing.poly) polys.push(new PolyOut2(enclosingRing));
+                enclosingRing.poly.addInterior(ring);
+              }
+            }
+            return polys;
+          }
+        }
+        class SweepLine2 {
+          constructor(queue) {
+            let comparator = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : Segment2.compare;
+            this.queue = queue;
+            this.tree = new Tree(comparator);
+            this.segments = [];
+          }
+          process(event) {
+            const segment = event.segment;
+            const newEvents = [];
+            if (event.consumedBy) {
+              if (event.isLeft) this.queue.remove(event.otherSE);
+              else this.tree.remove(segment);
+              return newEvents;
+            }
+            const node = event.isLeft ? this.tree.add(segment) : this.tree.find(segment);
+            if (!node) throw new Error("Unable to find segment #".concat(segment.id, " ") + "[".concat(segment.leftSE.point.x, ", ").concat(segment.leftSE.point.y, "] -> ") + "[".concat(segment.rightSE.point.x, ", ").concat(segment.rightSE.point.y, "] ") + "in SweepLine tree.");
+            let prevNode = node;
+            let nextNode = node;
+            let prevSeg = void 0;
+            let nextSeg = void 0;
+            while (prevSeg === void 0) {
+              prevNode = this.tree.prev(prevNode);
+              if (prevNode === null) prevSeg = null;
+              else if (prevNode.key.consumedBy === void 0) prevSeg = prevNode.key;
+            }
+            while (nextSeg === void 0) {
+              nextNode = this.tree.next(nextNode);
+              if (nextNode === null) nextSeg = null;
+              else if (nextNode.key.consumedBy === void 0) nextSeg = nextNode.key;
+            }
+            if (event.isLeft) {
+              let prevMySplitter = null;
+              if (prevSeg) {
+                const prevInter = prevSeg.getIntersection(segment);
+                if (prevInter !== null) {
+                  if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
+                  if (!prevSeg.isAnEndpoint(prevInter)) {
+                    const newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
+                    for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                      newEvents.push(newEventsFromSplit[i3]);
+                    }
+                  }
+                }
+              }
+              let nextMySplitter = null;
+              if (nextSeg) {
+                const nextInter = nextSeg.getIntersection(segment);
+                if (nextInter !== null) {
+                  if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
+                  if (!nextSeg.isAnEndpoint(nextInter)) {
+                    const newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
+                    for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                      newEvents.push(newEventsFromSplit[i3]);
+                    }
+                  }
+                }
+              }
+              if (prevMySplitter !== null || nextMySplitter !== null) {
+                let mySplitter = null;
+                if (prevMySplitter === null) mySplitter = nextMySplitter;
+                else if (nextMySplitter === null) mySplitter = prevMySplitter;
+                else {
+                  const cmpSplitters = SweepEvent2.comparePoints(prevMySplitter, nextMySplitter);
+                  mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
+                }
+                this.queue.remove(segment.rightSE);
+                newEvents.push(segment.rightSE);
+                const newEventsFromSplit = segment.split(mySplitter);
+                for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                  newEvents.push(newEventsFromSplit[i3]);
+                }
+              }
+              if (newEvents.length > 0) {
+                this.tree.remove(segment);
+                newEvents.push(event);
+              } else {
+                this.segments.push(segment);
+                segment.prev = prevSeg;
+              }
+            } else {
+              if (prevSeg && nextSeg) {
+                const inter = prevSeg.getIntersection(nextSeg);
+                if (inter !== null) {
+                  if (!prevSeg.isAnEndpoint(inter)) {
+                    const newEventsFromSplit = this._splitSafely(prevSeg, inter);
+                    for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                      newEvents.push(newEventsFromSplit[i3]);
+                    }
+                  }
+                  if (!nextSeg.isAnEndpoint(inter)) {
+                    const newEventsFromSplit = this._splitSafely(nextSeg, inter);
+                    for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                      newEvents.push(newEventsFromSplit[i3]);
+                    }
+                  }
+                }
+              }
+              this.tree.remove(segment);
+            }
+            return newEvents;
+          }
+          /* Safely split a segment that is currently in the datastructures
+           * IE - a segment other than the one that is currently being processed. */
+          _splitSafely(seg, pt2) {
+            this.tree.remove(seg);
+            const rightSE = seg.rightSE;
+            this.queue.remove(rightSE);
+            const newEvents = seg.split(pt2);
+            newEvents.push(rightSE);
+            if (seg.consumedBy === void 0) this.tree.add(seg);
+            return newEvents;
+          }
+        }
+        const POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1e6;
+        const POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1e6;
+        class Operation2 {
+          run(type2, geom, moreGeoms) {
+            operation2.type = type2;
+            rounder.reset();
+            const multipolys = [new MultiPolyIn2(geom, true)];
+            for (let i3 = 0, iMax = moreGeoms.length; i3 < iMax; i3++) {
+              multipolys.push(new MultiPolyIn2(moreGeoms[i3], false));
+            }
+            operation2.numMultiPolys = multipolys.length;
+            if (operation2.type === "difference") {
+              const subject = multipolys[0];
+              let i3 = 1;
+              while (i3 < multipolys.length) {
+                if (getBboxOverlap2(multipolys[i3].bbox, subject.bbox) !== null) i3++;
+                else multipolys.splice(i3, 1);
+              }
+            }
+            if (operation2.type === "intersection") {
+              for (let i3 = 0, iMax = multipolys.length; i3 < iMax; i3++) {
+                const mpA = multipolys[i3];
+                for (let j2 = i3 + 1, jMax = multipolys.length; j2 < jMax; j2++) {
+                  if (getBboxOverlap2(mpA.bbox, multipolys[j2].bbox) === null) return [];
+                }
+              }
+            }
+            const queue = new Tree(SweepEvent2.compare);
+            for (let i3 = 0, iMax = multipolys.length; i3 < iMax; i3++) {
+              const sweepEvents = multipolys[i3].getSweepEvents();
+              for (let j2 = 0, jMax = sweepEvents.length; j2 < jMax; j2++) {
+                queue.insert(sweepEvents[j2]);
+                if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
+                  throw new Error("Infinite loop when putting segment endpoints in a priority queue (queue size too big).");
+                }
+              }
+            }
+            const sweepLine = new SweepLine2(queue);
+            let prevQueueSize = queue.size;
+            let node = queue.pop();
+            while (node) {
+              const evt = node.key;
+              if (queue.size === prevQueueSize) {
+                const seg = evt.segment;
+                throw new Error("Unable to pop() ".concat(evt.isLeft ? "left" : "right", " SweepEvent ") + "[".concat(evt.point.x, ", ").concat(evt.point.y, "] from segment #").concat(seg.id, " ") + "[".concat(seg.leftSE.point.x, ", ").concat(seg.leftSE.point.y, "] -> ") + "[".concat(seg.rightSE.point.x, ", ").concat(seg.rightSE.point.y, "] from queue."));
+              }
+              if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
+                throw new Error("Infinite loop when passing sweep line over endpoints (queue size too big).");
+              }
+              if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
+                throw new Error("Infinite loop when passing sweep line over endpoints (too many sweep line segments).");
+              }
+              const newEvents = sweepLine.process(evt);
+              for (let i3 = 0, iMax = newEvents.length; i3 < iMax; i3++) {
+                const evt2 = newEvents[i3];
+                if (evt2.consumedBy === void 0) queue.insert(evt2);
+              }
+              prevQueueSize = queue.size;
+              node = queue.pop();
+            }
+            rounder.reset();
+            const ringsOut = RingOut2.factory(sweepLine.segments);
+            const result = new MultiPolyOut2(ringsOut);
+            return result.getGeom();
+          }
+        }
+        const operation2 = new Operation2();
+        const union2 = function(geom) {
+          for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+            moreGeoms[_key - 1] = arguments[_key];
+          }
+          return operation2.run("union", geom, moreGeoms);
+        };
+        const intersection2 = function(geom) {
+          for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
+            moreGeoms[_key2 - 1] = arguments[_key2];
+          }
+          return operation2.run("intersection", geom, moreGeoms);
+        };
+        const xor = function(geom) {
+          for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
+            moreGeoms[_key3 - 1] = arguments[_key3];
+          }
+          return operation2.run("xor", geom, moreGeoms);
+        };
+        const difference2 = function(subjectGeom) {
+          for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
+            clippingGeoms[_key4 - 1] = arguments[_key4];
+          }
+          return operation2.run("difference", subjectGeom, clippingGeoms);
+        };
+        var index = {
+          union: union2,
+          intersection: intersection2,
+          xor,
+          difference: difference2
+        };
+        return index;
+      });
     }
   });
 
   // node_modules/whatwg-fetch/fetch.js
-  var global2 = typeof globalThis !== "undefined" && globalThis || typeof self !== "undefined" && self || typeof global2 !== "undefined" && global2;
+  var g = typeof globalThis !== "undefined" && globalThis || typeof self !== "undefined" && self || // eslint-disable-next-line no-undef
+  typeof global !== "undefined" && global || {};
   var support = {
-    searchParams: "URLSearchParams" in global2,
-    iterable: "Symbol" in global2 && "iterator" in Symbol,
-    blob: "FileReader" in global2 && "Blob" in global2 && function() {
+    searchParams: "URLSearchParams" in g,
+    iterable: "Symbol" in g && "iterator" in Symbol,
+    blob: "FileReader" in g && "Blob" in g && function() {
       try {
         new Blob();
         return true;
-      } catch (e) {
+      } catch (e3) {
         return false;
       }
     }(),
-    formData: "FormData" in global2,
-    arrayBuffer: "ArrayBuffer" in global2
+    formData: "FormData" in g,
+    arrayBuffer: "ArrayBuffer" in g
   };
   function isDataView(obj) {
     return obj && DataView.prototype.isPrototypeOf(obj);
       }, this);
     } else if (Array.isArray(headers)) {
       headers.forEach(function(header) {
+        if (header.length != 2) {
+          throw new TypeError("Headers constructor: expected name/value pair to be length 2, found" + header.length);
+        }
         this.append(header[0], header[1]);
       }, this);
     } else if (headers) {
     Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
   }
   function consumed(body) {
+    if (body._noBody) return;
     if (body.bodyUsed) {
       return Promise.reject(new TypeError("Already read"));
     }
   function readBlobAsText(blob) {
     var reader = new FileReader();
     var promise = fileReaderReady(reader);
-    reader.readAsText(blob);
+    var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type);
+    var encoding = match ? match[1] : "utf-8";
+    reader.readAsText(blob, encoding);
     return promise;
   }
   function readArrayBufferAsText(buf) {
     var view = new Uint8Array(buf);
     var chars = new Array(view.length);
-    for (var i2 = 0; i2 < view.length; i2++) {
-      chars[i2] = String.fromCharCode(view[i2]);
+    for (var i3 = 0; i3 < view.length; i3++) {
+      chars[i3] = String.fromCharCode(view[i3]);
     }
     return chars.join("");
   }
       this.bodyUsed = this.bodyUsed;
       this._bodyInit = body;
       if (!body) {
+        this._noBody = true;
         this._bodyText = "";
       } else if (typeof body === "string") {
         this._bodyText = body;
           return Promise.resolve(new Blob([this._bodyText]));
         }
       };
-      this.arrayBuffer = function() {
-        if (this._bodyArrayBuffer) {
-          var isConsumed = consumed(this);
-          if (isConsumed) {
-            return isConsumed;
-          }
-          if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
-            return Promise.resolve(
-              this._bodyArrayBuffer.buffer.slice(
-                this._bodyArrayBuffer.byteOffset,
-                this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
-              )
-            );
-          } else {
-            return Promise.resolve(this._bodyArrayBuffer);
-          }
+    }
+    this.arrayBuffer = function() {
+      if (this._bodyArrayBuffer) {
+        var isConsumed = consumed(this);
+        if (isConsumed) {
+          return isConsumed;
+        } else if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
+          return Promise.resolve(
+            this._bodyArrayBuffer.buffer.slice(
+              this._bodyArrayBuffer.byteOffset,
+              this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
+            )
+          );
         } else {
-          return this.blob().then(readBlobAsArrayBuffer);
+          return Promise.resolve(this._bodyArrayBuffer);
         }
-      };
-    }
+      } else if (support.blob) {
+        return this.blob().then(readBlobAsArrayBuffer);
+      } else {
+        throw new Error("could not read as ArrayBuffer");
+      }
+    };
     this.text = function() {
       var rejected = consumed(this);
       if (rejected) {
     };
     return this;
   }
-  var methods = ["DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT"];
+  var methods = ["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"];
   function normalizeMethod(method) {
     var upcased = method.toUpperCase();
     return methods.indexOf(upcased) > -1 ? upcased : method;
     }
     this.method = normalizeMethod(options2.method || this.method || "GET");
     this.mode = options2.mode || this.mode || null;
-    this.signal = options2.signal || this.signal;
+    this.signal = options2.signal || this.signal || function() {
+      if ("AbortController" in g) {
+        var ctrl = new AbortController();
+        return ctrl.signal;
+      }
+    }();
     this.referrer = null;
     if ((this.method === "GET" || this.method === "HEAD") && body) {
       throw new TypeError("Body not allowed for GET or HEAD requests");
       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();
         }
       }
     }
       var key = parts.shift().trim();
       if (key) {
         var value = parts.join(":").trim();
-        headers.append(key, value);
+        try {
+          headers.append(key, value);
+        } catch (error) {
+          console.warn("Response " + error.message);
+        }
       }
     });
     return headers;
     }
     this.type = "default";
     this.status = options2.status === void 0 ? 200 : options2.status;
+    if (this.status < 200 || this.status > 599) {
+      throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].");
+    }
     this.ok = this.status >= 200 && this.status < 300;
     this.statusText = options2.statusText === void 0 ? "" : "" + options2.statusText;
     this.headers = new Headers(options2.headers);
     });
   };
   Response.error = function() {
-    var response = new Response(null, { status: 0, statusText: "" });
+    var response = new Response(null, { status: 200, statusText: "" });
+    response.ok = false;
+    response.status = 0;
     response.type = "error";
     return response;
   };
     }
     return new Response(null, { status, headers: { location: url } });
   };
-  var DOMException2 = global2.DOMException;
+  var DOMException2 = g.DOMException;
   try {
     new DOMException2();
   } catch (err) {
       }
       xhr.onload = function() {
         var options2 = {
-          status: xhr.status,
           statusText: xhr.statusText,
           headers: parseHeaders(xhr.getAllResponseHeaders() || "")
         };
+        if (request3.url.indexOf("file://") === 0 && (xhr.status < 200 || xhr.status > 599)) {
+          options2.status = 200;
+        } else {
+          options2.status = xhr.status;
+        }
         options2.url = "responseURL" in xhr ? xhr.responseURL : options2.headers.get("X-Request-URL");
         var body = "response" in xhr ? xhr.response : xhr.responseText;
         setTimeout(function() {
       };
       xhr.ontimeout = function() {
         setTimeout(function() {
-          reject(new TypeError("Network request failed"));
+          reject(new TypeError("Network request timed out"));
         }, 0);
       };
       xhr.onabort = function() {
       };
       function fixUrl(url) {
         try {
-          return url === "" && global2.location.href ? global2.location.href : url;
-        } catch (e) {
+          return url === "" && g.location.href ? g.location.href : url;
+        } catch (e3) {
           return url;
         }
       }
       if ("responseType" in xhr) {
         if (support.blob) {
           xhr.responseType = "blob";
-        } else if (support.arrayBuffer && request3.headers.get("Content-Type") && request3.headers.get("Content-Type").indexOf("application/octet-stream") !== -1) {
+        } else if (support.arrayBuffer) {
           xhr.responseType = "arraybuffer";
         }
       }
-      if (init2 && typeof init2.headers === "object" && !(init2.headers instanceof Headers)) {
+      if (init2 && typeof init2.headers === "object" && !(init2.headers instanceof Headers || g.Headers && init2.headers instanceof g.Headers)) {
+        var names = [];
         Object.getOwnPropertyNames(init2.headers).forEach(function(name) {
+          names.push(normalizeName(name));
           xhr.setRequestHeader(name, normalizeValue(init2.headers[name]));
         });
+        request3.headers.forEach(function(value, name) {
+          if (names.indexOf(name) === -1) {
+            xhr.setRequestHeader(name, value);
+          }
+        });
       } else {
         request3.headers.forEach(function(value, name) {
           xhr.setRequestHeader(name, value);
     });
   }
   fetch2.polyfill = true;
-  if (!global2.fetch) {
-    global2.fetch = fetch2;
-    global2.Headers = Headers;
-    global2.Request = Request;
-    global2.Response = Response;
+  if (!g.fetch) {
+    g.fetch = fetch2;
+    g.Headers = Headers;
+    g.Request = Request;
+    g.Response = Response;
   }
 
   // node_modules/abortcontroller-polyfill/dist/polyfill-patch-fetch.js
       }
     }
     function _defineProperties(target, props) {
-      for (var i2 = 0; i2 < props.length; i2++) {
-        var descriptor = props[i2];
+      for (var i3 = 0; i3 < props.length; i3++) {
+        var descriptor = props[i3];
         descriptor.enumerable = descriptor.enumerable || false;
         descriptor.configurable = true;
-        if ("value" in descriptor)
-          descriptor.writable = true;
+        if ("value" in descriptor) descriptor.writable = true;
         Object.defineProperty(target, descriptor.key, descriptor);
       }
     }
     function _createClass(Constructor, protoProps, staticProps) {
-      if (protoProps)
-        _defineProperties(Constructor.prototype, protoProps);
-      if (staticProps)
-        _defineProperties(Constructor, staticProps);
+      if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+      if (staticProps) _defineProperties(Constructor, staticProps);
+      Object.defineProperty(Constructor, "prototype", {
+        writable: false
+      });
       return Constructor;
     }
     function _inherits(subClass, superClass) {
           configurable: true
         }
       });
-      if (superClass)
-        _setPrototypeOf(subClass, superClass);
+      Object.defineProperty(subClass, "prototype", {
+        writable: false
+      });
+      if (superClass) _setPrototypeOf(subClass, superClass);
     }
-    function _getPrototypeOf(o) {
-      _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf2(o2) {
-        return o2.__proto__ || Object.getPrototypeOf(o2);
+    function _getPrototypeOf(o2) {
+      _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf2(o3) {
+        return o3.__proto__ || Object.getPrototypeOf(o3);
       };
-      return _getPrototypeOf(o);
+      return _getPrototypeOf(o2);
     }
-    function _setPrototypeOf(o, p) {
-      _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf2(o2, p2) {
-        o2.__proto__ = p2;
-        return o2;
+    function _setPrototypeOf(o2, p2) {
+      _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf2(o3, p3) {
+        o3.__proto__ = p3;
+        return o3;
       };
-      return _setPrototypeOf(o, p);
+      return _setPrototypeOf(o2, p2);
     }
     function _isNativeReflectConstruct() {
-      if (typeof Reflect === "undefined" || !Reflect.construct)
-        return false;
-      if (Reflect.construct.sham)
-        return false;
-      if (typeof Proxy === "function")
-        return true;
+      if (typeof Reflect === "undefined" || !Reflect.construct) return false;
+      if (Reflect.construct.sham) return false;
+      if (typeof Proxy === "function") return true;
       try {
         Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {
         }));
         return true;
-      } catch (e) {
+      } catch (e3) {
         return false;
       }
     }
     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);
     }
     function _superPropBase(object, property) {
       while (!Object.prototype.hasOwnProperty.call(object, property)) {
         object = _getPrototypeOf(object);
-        if (object === null)
-          break;
+        if (object === null) break;
       }
       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);
-          if (!base)
-            return;
-          var desc = Object.getOwnPropertyDescriptor(base, property2);
+        _get = function _get2(target, property, receiver) {
+          var base = _superPropBase(target, property);
+          if (!base) return;
+          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];
-          for (var i2 = 0, l = stack.length; i2 < l; i2++) {
-            if (stack[i2].callback === callback) {
-              stack.splice(i2, 1);
+          var stack = this.listeners[type2];
+          for (var i3 = 0, l2 = stack.length; i3 < l2; i3++) {
+            if (stack[i3].callback === callback) {
+              stack.splice(i3, 1);
               return;
             }
           }
           }
           var stack = this.listeners[event.type];
           var stackToCall = stack.slice();
-          for (var i2 = 0, l = stackToCall.length; i2 < l; i2++) {
-            var listener = stackToCall[i2];
+          for (var i3 = 0, l2 = stackToCall.length; i3 < l2; i3++) {
+            var listener = stackToCall[i3];
             try {
               listener.callback.call(this, event);
-            } catch (e) {
+            } catch (e3) {
               Promise.resolve().then(function() {
-                throw e;
+                throw e3;
               });
             }
             if (listener.options && listener.options.once) {
           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");
-          } catch (e) {
+          } catch (e3) {
             if (typeof document !== "undefined") {
               if (!document.createEvent) {
                 event = document.createEventObject();
               };
             }
           }
+          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);
         }
       }, {
           if (signal.aborted) {
             return Promise.reject(abortError);
           }
-          var cancellation = new Promise(function(_, reject) {
+          var cancellation = new Promise(function(_2, reject) {
             signal.addEventListener("abort", function() {
               return reject(abortError);
             }, {
   // modules/index.js
   var modules_exports = {};
   __export(modules_exports, {
+    LANGUAGE_SUFFIX_REGEX: () => LANGUAGE_SUFFIX_REGEX,
+    LocationManager: () => LocationManager,
     QAItem: () => QAItem,
     actionAddEntity: () => actionAddEntity,
     actionAddMember: () => actionAddMember,
     coreGraph: () => coreGraph,
     coreHistory: () => coreHistory,
     coreLocalizer: () => coreLocalizer,
-    coreLocations: () => coreLocations,
     coreTree: () => coreTree,
     coreUploader: () => coreUploader,
     coreValidator: () => coreValidator,
     d3: () => d3,
     debug: () => debug,
+    dmsCoordinatePair: () => dmsCoordinatePair,
+    dmsMatcher: () => dmsMatcher,
     fileFetcher: () => _mainFileFetcher,
     geoAngle: () => geoAngle,
     geoChooseEdge: () => geoChooseEdge,
     geoVecSubtract: () => geoVecSubtract,
     geoViewportEdge: () => geoViewportEdge,
     geoZoomToScale: () => geoZoomToScale,
+    likelyRawNumberFormat: () => likelyRawNumberFormat,
     localizer: () => _mainLocalizer,
-    locationManager: () => _mainLocations,
+    locationManager: () => _sharedLocationManager,
     modeAddArea: () => modeAddArea,
     modeAddLine: () => modeAddLine,
     modeAddNote: () => modeAddNote,
     osmInferRestriction: () => osmInferRestriction,
     osmIntersection: () => osmIntersection,
     osmIsInterestingTag: () => osmIsInterestingTag,
-    osmIsOldMultipolygonOuterMember: () => osmIsOldMultipolygonOuterMember,
     osmJoinWays: () => osmJoinWays,
     osmLanes: () => osmLanes,
     osmLifecyclePrefixes: () => osmLifecyclePrefixes,
     osmNode: () => osmNode,
     osmNodeGeometriesForTags: () => osmNodeGeometriesForTags,
     osmNote: () => osmNote,
-    osmOldMultipolygonOuterMember: () => osmOldMultipolygonOuterMember,
-    osmOldMultipolygonOuterMemberOfRelation: () => osmOldMultipolygonOuterMemberOfRelation,
     osmOneWayTags: () => osmOneWayTags,
     osmPavedTags: () => osmPavedTags,
     osmPointTags: () => osmPointTags,
     rendererMap: () => rendererMap,
     rendererPhotos: () => rendererPhotos,
     rendererTileLayer: () => rendererTileLayer,
-    serviceImproveOSM: () => improveOSM_default,
     serviceKartaview: () => kartaview_default,
     serviceKeepRight: () => keepRight_default,
     serviceMapRules: () => maprules_default,
+    serviceMapilio: () => mapilio_default,
     serviceMapillary: () => mapillary_default,
     serviceNominatim: () => nominatim_default,
     serviceNsi: () => nsi_default,
     serviceOsm: () => osm_default,
     serviceOsmWikibase: () => osm_wikibase_default,
     serviceOsmose: () => osmose_default,
+    servicePanoramax: () => panoramax_default,
     serviceStreetside: () => streetside_default,
     serviceTaginfo: () => taginfo_default,
     serviceVectorTile: () => vector_tile_default,
+    serviceVegbilder: () => vegbilder_default,
     serviceWikidata: () => wikidata_default,
     serviceWikipedia: () => wikipedia_default,
     services: () => services,
     svgLabels: () => svgLabels,
     svgLayers: () => svgLayers,
     svgLines: () => svgLines,
+    svgMapilioImages: () => svgMapilioImages,
     svgMapillaryImages: () => svgMapillaryImages,
     svgMapillarySigns: () => svgMapillarySigns,
     svgMarkerSegments: () => svgMarkerSegments,
     svgMidpoints: () => svgMidpoints,
     svgNotes: () => svgNotes,
     svgOsm: () => svgOsm,
+    svgPanoramaxImages: () => svgPanoramaxImages,
     svgPassiveVertex: () => svgPassiveVertex,
     svgPath: () => svgPath,
     svgPointTransform: () => svgPointTransform,
     svgTagPattern: () => svgTagPattern,
     svgTouch: () => svgTouch,
     svgTurns: () => svgTurns,
+    svgVegbilder: () => svgVegbilder,
     svgVertices: () => svgVertices,
     t: () => _t,
     uiAccount: () => uiAccount,
     uiFieldAccess: () => uiFieldAccess,
     uiFieldAddress: () => uiFieldAddress,
     uiFieldCheck: () => uiFieldCheck,
+    uiFieldColour: () => uiFieldText,
     uiFieldCombo: () => uiFieldCombo,
-    uiFieldCycleway: () => uiFieldCycleway,
     uiFieldDefaultCheck: () => uiFieldCheck,
+    uiFieldDirectionalCombo: () => uiFieldDirectionalCombo,
     uiFieldEmail: () => uiFieldText,
     uiFieldHelp: () => uiFieldHelp,
     uiFieldIdentifier: () => uiFieldText,
     uiFormFields: () => uiFormFields,
     uiFullScreen: () => uiFullScreen,
     uiGeolocate: () => uiGeolocate,
-    uiImproveOsmComments: () => uiImproveOsmComments,
-    uiImproveOsmDetails: () => uiImproveOsmDetails,
-    uiImproveOsmEditor: () => uiImproveOsmEditor,
-    uiImproveOsmHeader: () => uiImproveOsmHeader,
     uiInfo: () => uiInfo,
     uiInfoPanels: () => uiInfoPanels,
     uiInit: () => uiInit,
     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,
     validationMismatchedGeometry: () => validationMismatchedGeometry,
     validationMissingRole: () => validationMissingRole,
     validationMissingTag: () => validationMissingTag,
+    validationMutuallyExclusiveTags: () => validationMutuallyExclusiveTags,
     validationOutdatedTags: () => validationOutdatedTags,
     validationPrivateData: () => validationPrivateData,
     validationSuspiciousName: () => validationSuspiciousName,
       forwards: "backward",
       backwards: "forward"
     };
+    const valueReplacementsExceptions = {
+      "side": [
+        { highway: "cyclist_waiting_aid" }
+      ]
+    };
     var roleReplacements = {
       forward: "backward",
       backward: "forward",
       NNW: "SSE"
     };
     function reverseKey(key) {
-      for (var i2 = 0; i2 < keyReplacements.length; ++i2) {
-        var replacement = keyReplacements[i2];
+      for (var i3 = 0; i3 < keyReplacements.length; ++i3) {
+        var replacement = keyReplacements[i3];
         if (replacement[0].test(key)) {
           return key.replace(replacement[0], replacement[1]);
         }
       }
       return key;
     }
-    function reverseValue(key, value, includeAbsolute) {
-      if (ignoreKey.test(key))
-        return value;
+    function reverseValue(key, value, includeAbsolute, allTags) {
+      if (ignoreKey.test(key)) return value;
       if (turn_lanes.test(key)) {
         return value;
       } else if (key === "incline" && numeric.test(value)) {
-        return value.replace(numeric, function(_, sign2) {
+        return value.replace(numeric, function(_2, sign2) {
           return sign2 === "-" ? "" : "-";
         });
       } 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(";");
+      }
+      if (valueReplacementsExceptions[key] && valueReplacementsExceptions[key].some(
+        (exceptionTags) => Object.keys(exceptionTags).every((k2) => {
+          const v2 = exceptionTags[k2];
+          return allTags[k2] && (v2 === "*" || allTags[k2] === v2);
+        })
+      )) {
+        return value;
       }
       return valueReplacements[value] || value;
     }
     function reverseNodeTags(graph, nodeIDs) {
-      for (var i2 = 0; i2 < nodeIDs.length; i2++) {
-        var node = graph.hasEntity(nodeIDs[i2]);
-        if (!node || !Object.keys(node.tags).length)
-          continue;
+      for (var i3 = 0; i3 < nodeIDs.length; i3++) {
+        var node = graph.hasEntity(nodeIDs[i3]);
+        if (!node || !Object.keys(node.tags).length) continue;
         var tags = {};
         for (var key in node.tags) {
-          tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID);
+          tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID, node.tags);
         }
         graph = graph.replace(node.update({ tags }));
       }
       var tags = {};
       var role;
       for (var key in way.tags) {
-        tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
+        tags[reverseKey(key)] = reverseValue(key, way.tags[key], false, way.tags);
       }
       graph.parentRelations(way).forEach(function(relation) {
         relation.members.forEach(function(member, index) {
     };
     action.disabled = function(graph) {
       var entity = graph.hasEntity(entityID);
-      if (!entity || entity.type === "way")
-        return false;
+      if (!entity || entity.type === "way") return false;
       for (var key in entity.tags) {
         var value = entity.tags[key];
-        if (reverseKey(key) !== key || reverseValue(key, value, true) !== value) {
+        if (reverseKey(key) !== key || reverseValue(key, value, true, entity.tags) !== value) {
           return false;
         }
       }
     return action;
   }
 
-  // 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;
-  }
-  var osmLifecyclePrefixes = {
-    proposed: true,
-    planned: true,
-    construction: true,
-    disused: true,
-    abandoned: true,
-    was: true,
-    dismantled: true,
-    razed: true,
-    demolished: true,
-    destroyed: true,
-    removed: true,
-    obliterated: true,
-    intermittent: true
-  };
-  function osmRemoveLifecyclePrefix(key) {
-    const keySegments = key.split(":");
-    if (keySegments.length === 1)
-      return key;
-    if (keySegments[0] in osmLifecyclePrefixes) {
-      return key.slice(keySegments[0].length + 1);
-    }
-    return key;
-  }
-  var osmAreaKeys = {};
-  function osmSetAreaKeys(value) {
-    osmAreaKeys = value;
-  }
-  var osmAreaKeysExceptions = {
-    highway: {
-      elevator: true,
-      rest_area: true,
-      services: true
-    },
-    public_transport: {
-      platform: true
-    },
-    railway: {
-      platform: true,
-      roundhouse: true,
-      station: true,
-      traverser: true,
-      turntable: true,
-      wash: true
-    },
-    waterway: {
-      dam: true
-    }
-  };
-  function osmTagSuggestingArea(tags) {
-    if (tags.area === "yes")
-      return { area: "yes" };
-    if (tags.area === "no")
-      return null;
-    var returnTags = {};
-    for (var realKey in tags) {
-      const key = osmRemoveLifecyclePrefix(realKey);
-      if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
-        returnTags[realKey] = tags[realKey];
-        return returnTags;
-      }
-      if (key in osmAreaKeysExceptions && tags[key] in osmAreaKeysExceptions[key]) {
-        returnTags[realKey] = tags[realKey];
-        return returnTags;
-      }
-    }
-    return null;
-  }
-  var osmPointTags = {};
-  function osmSetPointTags(value) {
-    osmPointTags = value;
-  }
-  var osmVertexTags = {};
-  function osmSetVertexTags(value) {
-    osmVertexTags = value;
-  }
-  function osmNodeGeometriesForTags(nodeTags) {
-    var geometries = {};
-    for (var key in nodeTags) {
-      if (osmPointTags[key] && (osmPointTags[key]["*"] || osmPointTags[key][nodeTags[key]])) {
-        geometries.point = true;
-      }
-      if (osmVertexTags[key] && (osmVertexTags[key]["*"] || osmVertexTags[key][nodeTags[key]])) {
-        geometries.vertex = true;
-      }
-      if (geometries.point && geometries.vertex)
-        break;
-    }
-    return geometries;
-  }
-  var osmOneWayTags = {
-    "aerialway": {
-      "chair_lift": true,
-      "drag_lift": true,
-      "j-bar": true,
-      "magic_carpet": true,
-      "mixed_lift": true,
-      "platter": true,
-      "rope_tow": true,
-      "t-bar": true,
-      "zip_line": true
-    },
-    "highway": {
-      "motorway": true
-    },
-    "junction": {
-      "circular": true,
-      "roundabout": true
-    },
-    "man_made": {
-      "goods_conveyor": true,
-      "piste:halfpipe": true
-    },
-    "piste:type": {
-      "downhill": true,
-      "sled": true,
-      "yes": true
-    },
-    "seamark:type": {
-      "separation_lane": true,
-      "separation_roundabout": true
-    },
-    "waterway": {
-      "canal": true,
-      "ditch": true,
-      "drain": true,
-      "fish_pass": true,
-      "river": true,
-      "stream": true,
-      "tidal_channel": true
-    }
-  };
-  var osmPavedTags = {
-    "surface": {
-      "paved": true,
-      "asphalt": true,
-      "concrete": true,
-      "chipseal": true,
-      "concrete:lanes": true,
-      "concrete:plates": true
-    },
-    "tracktype": {
-      "grade1": true
-    }
-  };
-  var osmSemipavedTags = {
-    "surface": {
-      "cobblestone": true,
-      "cobblestone:flattened": true,
-      "unhewn_cobblestone": true,
-      "sett": true,
-      "paving_stones": true,
-      "metal": true,
-      "wood": true
-    }
-  };
-  var osmRightSideIsInsideTags = {
-    "natural": {
-      "cliff": true,
-      "coastline": "coastline"
-    },
-    "barrier": {
-      "retaining_wall": true,
-      "kerb": true,
-      "guard_rail": true,
-      "city_wall": true
-    },
-    "man_made": {
-      "embankment": true
-    },
-    "waterway": {
-      "weir": true
-    }
-  };
-  var osmRoutableHighwayTagValues = {
-    motorway: true,
-    trunk: true,
-    primary: true,
-    secondary: true,
-    tertiary: true,
-    residential: true,
-    motorway_link: true,
-    trunk_link: true,
-    primary_link: true,
-    secondary_link: true,
-    tertiary_link: true,
-    unclassified: true,
-    road: true,
-    service: true,
-    track: true,
-    living_street: true,
-    bus_guideway: true,
-    path: true,
-    footway: true,
-    cycleway: true,
-    bridleway: true,
-    pedestrian: true,
-    corridor: true,
-    steps: true
-  };
-  var osmPathHighwayTagValues = {
-    path: true,
-    footway: true,
-    cycleway: true,
-    bridleway: true,
-    pedestrian: true,
-    corridor: true,
-    steps: true
-  };
-  var osmRailwayTrackTagValues = {
-    rail: true,
-    light_rail: true,
-    tram: true,
-    subway: true,
-    monorail: true,
-    funicular: true,
-    miniature: true,
-    narrow_gauge: true,
-    disused: true,
-    preserved: true
-  };
-  var osmFlowingWaterwayTagValues = {
-    canal: true,
-    ditch: true,
-    drain: true,
-    fish_pass: true,
-    river: true,
-    stream: true,
-    tidal_channel: true
-  };
-
   // node_modules/d3-array/src/ascending.js
-  function ascending(a, b) {
-    return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+  function ascending(a2, b2) {
+    return a2 == null || b2 == null ? NaN : a2 < b2 ? -1 : a2 > b2 ? 1 : a2 >= b2 ? 0 : NaN;
   }
 
   // node_modules/d3-array/src/descending.js
-  function descending(a, b) {
-    return a == null || b == null ? NaN : b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+  function descending(a2, b2) {
+    return a2 == null || b2 == null ? NaN : b2 < a2 ? -1 : b2 > a2 ? 1 : b2 >= a2 ? 0 : NaN;
   }
 
   // node_modules/d3-array/src/bisector.js
     let compare1, compare2, delta;
     if (f2.length !== 2) {
       compare1 = ascending;
-      compare2 = (d, x) => ascending(f2(d), x);
-      delta = (d, x) => f2(d) - x;
+      compare2 = (d2, x2) => ascending(f2(d2), x2);
+      delta = (d2, x2) => f2(d2) - x2;
     } else {
       compare1 = f2 === ascending || f2 === descending ? f2 : zero;
       compare2 = f2;
       delta = f2;
     }
-    function left(a, x, lo = 0, hi = a.length) {
+    function left(a2, x2, lo = 0, hi = a2.length) {
       if (lo < hi) {
-        if (compare1(x, x) !== 0)
-          return hi;
+        if (compare1(x2, x2) !== 0) return hi;
         do {
           const mid = lo + hi >>> 1;
-          if (compare2(a[mid], x) < 0)
-            lo = mid + 1;
-          else
-            hi = mid;
+          if (compare2(a2[mid], x2) < 0) lo = mid + 1;
+          else hi = mid;
         } while (lo < hi);
       }
       return lo;
     }
-    function right(a, x, lo = 0, hi = a.length) {
+    function right(a2, x2, lo = 0, hi = a2.length) {
       if (lo < hi) {
-        if (compare1(x, x) !== 0)
-          return hi;
+        if (compare1(x2, x2) !== 0) return hi;
         do {
           const mid = lo + hi >>> 1;
-          if (compare2(a[mid], x) <= 0)
-            lo = mid + 1;
-          else
-            hi = mid;
+          if (compare2(a2[mid], x2) <= 0) lo = mid + 1;
+          else hi = mid;
         } while (lo < hi);
       }
       return lo;
     }
-    function center(a, x, lo = 0, hi = a.length) {
-      const i2 = left(a, x, lo, hi - 1);
-      return i2 > lo && delta(a[i2 - 1], x) > -delta(a[i2], x) ? i2 - 1 : i2;
+    function center(a2, x2, lo = 0, hi = a2.length) {
+      const i3 = left(a2, x2, lo, hi - 1);
+      return i3 > lo && delta(a2[i3 - 1], x2) > -delta(a2[i3], x2) ? i3 - 1 : i3;
     }
     return { left, center, right };
   }
   }
 
   // node_modules/d3-array/src/number.js
-  function number(x) {
-    return x === null ? NaN : +x;
+  function number(x2) {
+    return x2 === null ? NaN : +x2;
   }
   function* numbers(values, valueof) {
     if (valueof === void 0) {
       this._partials = new Float64Array(32);
       this._n = 0;
     }
-    add(x) {
-      const p = this._partials;
-      let i2 = 0;
+    add(x2) {
+      const p2 = this._partials;
+      let i3 = 0;
       for (let j2 = 0; j2 < this._n && j2 < 32; j2++) {
-        const y = p[j2], hi = x + y, lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
-        if (lo)
-          p[i2++] = lo;
-        x = hi;
+        const y2 = p2[j2], hi = x2 + y2, lo = Math.abs(x2) < Math.abs(y2) ? x2 - (hi - y2) : y2 - (hi - x2);
+        if (lo) p2[i3++] = lo;
+        x2 = hi;
       }
-      p[i2] = x;
-      this._n = i2 + 1;
+      p2[i3] = x2;
+      this._n = i3 + 1;
       return this;
     }
     valueOf() {
-      const p = this._partials;
-      let n2 = this._n, x, y, lo, hi = 0;
-      if (n2 > 0) {
-        hi = p[--n2];
-        while (n2 > 0) {
-          x = hi;
-          y = p[--n2];
-          hi = x + y;
-          lo = y - (hi - x);
-          if (lo)
-            break;
-        }
-        if (n2 > 0 && (lo < 0 && p[n2 - 1] < 0 || lo > 0 && p[n2 - 1] > 0)) {
-          y = lo * 2;
-          x = hi + y;
-          if (y == x - hi)
-            hi = x;
+      const p2 = this._partials;
+      let n3 = this._n, x2, y2, lo, hi = 0;
+      if (n3 > 0) {
+        hi = p2[--n3];
+        while (n3 > 0) {
+          x2 = hi;
+          y2 = p2[--n3];
+          hi = x2 + y2;
+          lo = y2 - (hi - x2);
+          if (lo) break;
+        }
+        if (n3 > 0 && (lo < 0 && p2[n3 - 1] < 0 || lo > 0 && p2[n3 - 1] > 0)) {
+          y2 = lo * 2;
+          x2 = hi + y2;
+          if (y2 == x2 - hi) hi = x2;
         }
       }
       return hi;
   };
 
   // node_modules/d3-array/src/sort.js
-  function compareDefined(compare = ascending) {
-    if (compare === ascending)
-      return ascendingDefined;
-    if (typeof compare !== "function")
-      throw new TypeError("compare is not a function");
-    return (a, b) => {
-      const x = compare(a, b);
-      if (x || x === 0)
-        return x;
-      return (compare(b, b) === 0) - (compare(a, a) === 0);
+  function compareDefined(compare2 = ascending) {
+    if (compare2 === ascending) return ascendingDefined;
+    if (typeof compare2 !== "function") throw new TypeError("compare is not a function");
+    return (a2, b2) => {
+      const x2 = compare2(a2, b2);
+      if (x2 || x2 === 0) return x2;
+      return (compare2(b2, b2) === 0) - (compare2(a2, a2) === 0);
     };
   }
-  function ascendingDefined(a, b) {
-    return (a == null || !(a >= a)) - (b == null || !(b >= b)) || (a < b ? -1 : a > b ? 1 : 0);
+  function ascendingDefined(a2, b2) {
+    return (a2 == null || !(a2 >= a2)) - (b2 == null || !(b2 >= b2)) || (a2 < b2 ? -1 : a2 > b2 ? 1 : 0);
   }
 
   // node_modules/d3-array/src/ticks.js
   var e5 = Math.sqrt(10);
   var e2 = Math.sqrt(2);
   function ticks(start2, stop, count) {
-    var reverse, i2 = -1, n2, ticks2, step;
+    var reverse, i3 = -1, n3, ticks2, step;
     stop = +stop, start2 = +start2, count = +count;
-    if (start2 === stop && count > 0)
-      return [start2];
-    if (reverse = stop < start2)
-      n2 = start2, start2 = stop, stop = n2;
-    if ((step = tickIncrement(start2, stop, count)) === 0 || !isFinite(step))
-      return [];
+    if (start2 === stop && count > 0) return [start2];
+    if (reverse = stop < start2) n3 = start2, start2 = stop, stop = n3;
+    if ((step = tickIncrement(start2, stop, count)) === 0 || !isFinite(step)) return [];
     if (step > 0) {
       let r0 = Math.round(start2 / step), r1 = Math.round(stop / step);
-      if (r0 * step < start2)
-        ++r0;
-      if (r1 * step > stop)
-        --r1;
-      ticks2 = new Array(n2 = r1 - r0 + 1);
-      while (++i2 < n2)
-        ticks2[i2] = (r0 + i2) * step;
+      if (r0 * step < start2) ++r0;
+      if (r1 * step > stop) --r1;
+      ticks2 = new Array(n3 = r1 - r0 + 1);
+      while (++i3 < n3) ticks2[i3] = (r0 + i3) * step;
     } else {
       step = -step;
       let r0 = Math.round(start2 * step), r1 = Math.round(stop * step);
-      if (r0 / step < start2)
-        ++r0;
-      if (r1 / step > stop)
-        --r1;
-      ticks2 = new Array(n2 = r1 - r0 + 1);
-      while (++i2 < n2)
-        ticks2[i2] = (r0 + i2) / step;
-    }
-    if (reverse)
-      ticks2.reverse();
+      if (r0 / step < start2) ++r0;
+      if (r1 / step > stop) --r1;
+      ticks2 = new Array(n3 = r1 - r0 + 1);
+      while (++i3 < n3) ticks2[i3] = (r0 + i3) / step;
+    }
+    if (reverse) ticks2.reverse();
     return ticks2;
   }
   function tickIncrement(start2, stop, count) {
   }
   function tickStep(start2, stop, count) {
     var step0 = Math.abs(stop - start2) / Math.max(0, count), step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), error = step0 / step1;
-    if (error >= e10)
-      step1 *= 10;
-    else if (error >= e5)
-      step1 *= 5;
-    else if (error >= e2)
-      step1 *= 2;
+    if (error >= e10) step1 *= 10;
+    else if (error >= e5) step1 *= 5;
+    else if (error >= e2) step1 *= 2;
     return stop < start2 ? -step1 : step1;
   }
 
   }
 
   // node_modules/d3-array/src/quickselect.js
-  function quickselect(array2, k, left = 0, right = array2.length - 1, compare) {
-    compare = compare === void 0 ? ascendingDefined : compareDefined(compare);
+  function quickselect(array2, k2, left = 0, right = array2.length - 1, compare2) {
+    compare2 = compare2 === void 0 ? ascendingDefined : compareDefined(compare2);
     while (right > left) {
       if (right - left > 600) {
-        const n2 = right - left + 1;
-        const m = k - left + 1;
-        const z = Math.log(n2);
-        const s = 0.5 * Math.exp(2 * z / 3);
-        const sd = 0.5 * Math.sqrt(z * s * (n2 - s) / n2) * (m - n2 / 2 < 0 ? -1 : 1);
-        const newLeft = Math.max(left, Math.floor(k - m * s / n2 + sd));
-        const newRight = Math.min(right, Math.floor(k + (n2 - m) * s / n2 + sd));
-        quickselect(array2, k, newLeft, newRight, compare);
-      }
-      const t = array2[k];
-      let i2 = left;
+        const n3 = right - left + 1;
+        const m2 = k2 - left + 1;
+        const z2 = Math.log(n3);
+        const s2 = 0.5 * Math.exp(2 * z2 / 3);
+        const sd = 0.5 * Math.sqrt(z2 * s2 * (n3 - s2) / n3) * (m2 - n3 / 2 < 0 ? -1 : 1);
+        const newLeft = Math.max(left, Math.floor(k2 - m2 * s2 / n3 + sd));
+        const newRight = Math.min(right, Math.floor(k2 + (n3 - m2) * s2 / n3 + sd));
+        quickselect(array2, k2, newLeft, newRight, compare2);
+      }
+      const t2 = array2[k2];
+      let i3 = left;
       let j2 = right;
-      swap(array2, left, k);
-      if (compare(array2[right], t) > 0)
-        swap(array2, left, right);
-      while (i2 < j2) {
-        swap(array2, i2, j2), ++i2, --j2;
-        while (compare(array2[i2], t) < 0)
-          ++i2;
-        while (compare(array2[j2], t) > 0)
-          --j2;
-      }
-      if (compare(array2[left], t) === 0)
-        swap(array2, left, j2);
-      else
-        ++j2, swap(array2, j2, right);
-      if (j2 <= k)
-        left = j2 + 1;
-      if (k <= j2)
-        right = j2 - 1;
+      swap(array2, left, k2);
+      if (compare2(array2[right], t2) > 0) swap(array2, left, right);
+      while (i3 < j2) {
+        swap(array2, i3, j2), ++i3, --j2;
+        while (compare2(array2[i3], t2) < 0) ++i3;
+        while (compare2(array2[j2], t2) > 0) --j2;
+      }
+      if (compare2(array2[left], t2) === 0) swap(array2, left, j2);
+      else ++j2, swap(array2, j2, right);
+      if (j2 <= k2) left = j2 + 1;
+      if (k2 <= j2) right = j2 - 1;
     }
     return array2;
   }
-  function swap(array2, i2, j2) {
-    const t = array2[i2];
-    array2[i2] = array2[j2];
-    array2[j2] = t;
+  function swap(array2, i3, j2) {
+    const t2 = array2[i3];
+    array2[i3] = array2[j2];
+    array2[j2] = t2;
   }
 
   // node_modules/d3-array/src/quantile.js
-  function quantile(values, p, valueof) {
+  function quantile(values, p2, valueof) {
     values = Float64Array.from(numbers(values, valueof));
-    if (!(n2 = values.length))
-      return;
-    if ((p = +p) <= 0 || n2 < 2)
-      return min(values);
-    if (p >= 1)
-      return max(values);
-    var n2, i2 = (n2 - 1) * p, i0 = Math.floor(i2), value0 = max(quickselect(values, i0).subarray(0, i0 + 1)), value1 = min(values.subarray(i0 + 1));
-    return value0 + (value1 - value0) * (i2 - i0);
+    if (!(n3 = values.length)) return;
+    if ((p2 = +p2) <= 0 || n3 < 2) return min(values);
+    if (p2 >= 1) return max(values);
+    var n3, i3 = (n3 - 1) * p2, i0 = Math.floor(i3), value0 = max(quickselect(values, i0).subarray(0, i0 + 1)), value1 = min(values.subarray(i0 + 1));
+    return value0 + (value1 - value0) * (i3 - i0);
   }
 
   // node_modules/d3-array/src/median.js
     return Array.from(flatten(arrays));
   }
 
+  // node_modules/d3-array/src/pairs.js
+  function pairs(values, pairof = pair) {
+    const pairs2 = [];
+    let previous;
+    let first = false;
+    for (const value of values) {
+      if (first) pairs2.push(pairof(previous, value));
+      previous = value;
+      first = true;
+    }
+    return pairs2;
+  }
+  function pair(a2, b2) {
+    return [a2, b2];
+  }
+
   // node_modules/d3-array/src/range.js
   function range(start2, stop, step) {
-    start2 = +start2, stop = +stop, step = (n2 = arguments.length) < 2 ? (stop = start2, start2 = 0, 1) : n2 < 3 ? 1 : +step;
-    var i2 = -1, n2 = Math.max(0, Math.ceil((stop - start2) / step)) | 0, range3 = new Array(n2);
-    while (++i2 < n2) {
-      range3[i2] = start2 + i2 * step;
+    start2 = +start2, stop = +stop, step = (n3 = arguments.length) < 2 ? (stop = start2, start2 = 0, 1) : n3 < 3 ? 1 : +step;
+    var i3 = -1, n3 = Math.max(0, Math.ceil((stop - start2) / step)) | 0, range3 = new Array(n3);
+    while (++i3 < n3) {
+      range3[i3] = start2 + i3 * step;
     }
     return range3;
   }
   var exp = Math.exp;
   var log = Math.log;
   var sin = Math.sin;
-  var sign = Math.sign || function(x) {
-    return x > 0 ? 1 : x < 0 ? -1 : 0;
+  var sign = Math.sign || function(x2) {
+    return x2 > 0 ? 1 : x2 < 0 ? -1 : 0;
   };
   var sqrt = Math.sqrt;
   var tan = Math.tan;
-  function acos(x) {
-    return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
+  function acos(x2) {
+    return x2 > 1 ? 0 : x2 < -1 ? pi : Math.acos(x2);
   }
-  function asin(x) {
-    return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
+  function asin(x2) {
+    return x2 > 1 ? halfPi : x2 < -1 ? -halfPi : Math.asin(x2);
   }
 
   // node_modules/d3-geo/src/noop.js
       streamGeometry(object.geometry, stream);
     },
     FeatureCollection: function(object, stream) {
-      var features2 = object.features, i2 = -1, n2 = features2.length;
-      while (++i2 < n2)
-        streamGeometry(features2[i2].geometry, stream);
+      var features = object.features, i3 = -1, n3 = features.length;
+      while (++i3 < n3) streamGeometry(features[i3].geometry, stream);
     }
   };
   var streamGeometryType = {
       stream.point(object[0], object[1], object[2]);
     },
     MultiPoint: function(object, stream) {
-      var coordinates = object.coordinates, i2 = -1, n2 = coordinates.length;
-      while (++i2 < n2)
-        object = coordinates[i2], stream.point(object[0], object[1], object[2]);
+      var coordinates = object.coordinates, i3 = -1, n3 = coordinates.length;
+      while (++i3 < n3) object = coordinates[i3], stream.point(object[0], object[1], object[2]);
     },
     LineString: function(object, stream) {
       streamLine(object.coordinates, stream, 0);
     },
     MultiLineString: function(object, stream) {
-      var coordinates = object.coordinates, i2 = -1, n2 = coordinates.length;
-      while (++i2 < n2)
-        streamLine(coordinates[i2], stream, 0);
+      var coordinates = object.coordinates, i3 = -1, n3 = coordinates.length;
+      while (++i3 < n3) streamLine(coordinates[i3], stream, 0);
     },
     Polygon: function(object, stream) {
       streamPolygon(object.coordinates, stream);
     },
     MultiPolygon: function(object, stream) {
-      var coordinates = object.coordinates, i2 = -1, n2 = coordinates.length;
-      while (++i2 < n2)
-        streamPolygon(coordinates[i2], stream);
+      var coordinates = object.coordinates, i3 = -1, n3 = coordinates.length;
+      while (++i3 < n3) streamPolygon(coordinates[i3], stream);
     },
     GeometryCollection: function(object, stream) {
-      var geometries = object.geometries, i2 = -1, n2 = geometries.length;
-      while (++i2 < n2)
-        streamGeometry(geometries[i2], stream);
+      var geometries = object.geometries, i3 = -1, n3 = geometries.length;
+      while (++i3 < n3) streamGeometry(geometries[i3], stream);
     }
   };
   function streamLine(coordinates, stream, closed) {
-    var i2 = -1, n2 = coordinates.length - closed, coordinate;
+    var i3 = -1, n3 = coordinates.length - closed, coordinate;
     stream.lineStart();
-    while (++i2 < n2)
-      coordinate = coordinates[i2], stream.point(coordinate[0], coordinate[1], coordinate[2]);
+    while (++i3 < n3) coordinate = coordinates[i3], stream.point(coordinate[0], coordinate[1], coordinate[2]);
     stream.lineEnd();
   }
   function streamPolygon(coordinates, stream) {
-    var i2 = -1, n2 = coordinates.length;
+    var i3 = -1, n3 = coordinates.length;
     stream.polygonStart();
-    while (++i2 < n2)
-      streamLine(coordinates[i2], stream, 1);
+    while (++i3 < n3) streamLine(coordinates[i3], stream, 1);
     stream.polygonEnd();
   }
   function stream_default(object, stream) {
   function areaPoint(lambda, phi) {
     lambda *= radians, phi *= radians;
     phi = phi / 2 + quarterPi;
-    var dLambda = lambda - lambda0, sdLambda = dLambda >= 0 ? 1 : -1, adLambda = sdLambda * dLambda, cosPhi = cos(phi), sinPhi = sin(phi), k = sinPhi0 * sinPhi, u = cosPhi0 * cosPhi + k * cos(adLambda), v = k * sdLambda * sin(adLambda);
-    areaRingSum.add(atan2(v, u));
+    var dLambda = lambda - lambda0, sdLambda = dLambda >= 0 ? 1 : -1, adLambda = sdLambda * dLambda, cosPhi = cos(phi), sinPhi = sin(phi), k2 = sinPhi0 * sinPhi, u2 = cosPhi0 * cosPhi + k2 * cos(adLambda), v2 = k2 * sdLambda * sin(adLambda);
+    areaRingSum.add(atan2(v2, u2));
     lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
   }
   function area_default(object) {
     var lambda = spherical2[0], phi = spherical2[1], cosPhi = cos(phi);
     return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
   }
-  function cartesianDot(a, b) {
-    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  function cartesianDot(a2, b2) {
+    return a2[0] * b2[0] + a2[1] * b2[1] + a2[2] * b2[2];
   }
-  function cartesianCross(a, b) {
-    return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
+  function cartesianCross(a2, b2) {
+    return [a2[1] * b2[2] - a2[2] * b2[1], a2[2] * b2[0] - a2[0] * b2[2], a2[0] * b2[1] - a2[1] * b2[0]];
   }
-  function cartesianAddInPlace(a, b) {
-    a[0] += b[0], a[1] += b[1], a[2] += b[2];
+  function cartesianAddInPlace(a2, b2) {
+    a2[0] += b2[0], a2[1] += b2[1], a2[2] += b2[2];
   }
-  function cartesianScale(vector, k) {
-    return [vector[0] * k, vector[1] * k, vector[2] * k];
+  function cartesianScale(vector, k2) {
+    return [vector[0] * k2, vector[1] * k2, vector[2] * k2];
   }
-  function cartesianNormalizeInPlace(d) {
-    var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
-    d[0] /= l, d[1] /= l, d[2] /= l;
+  function cartesianNormalizeInPlace(d2) {
+    var l2 = sqrt(d2[0] * d2[0] + d2[1] * d2[1] + d2[2] * d2[2]);
+    d2[0] /= l2, d2[1] /= l2, d2[2] /= l2;
   }
 
   // node_modules/d3-geo/src/bounds.js
       boundsStream.point = boundsPoint;
       boundsStream.lineStart = boundsLineStart;
       boundsStream.lineEnd = boundsLineEnd;
-      if (areaRingSum < 0)
-        lambda02 = -(lambda1 = 180), phi0 = -(phi1 = 90);
-      else if (deltaSum > epsilon)
-        phi1 = 90;
-      else if (deltaSum < -epsilon)
-        phi0 = -90;
+      if (areaRingSum < 0) lambda02 = -(lambda1 = 180), phi0 = -(phi1 = 90);
+      else if (deltaSum > epsilon) phi1 = 90;
+      else if (deltaSum < -epsilon) phi0 = -90;
       range2[0] = lambda02, range2[1] = lambda1;
     },
     sphere: function() {
   };
   function boundsPoint(lambda, phi) {
     ranges.push(range2 = [lambda02 = lambda, lambda1 = lambda]);
-    if (phi < phi0)
-      phi0 = phi;
-    if (phi > phi1)
-      phi1 = phi;
+    if (phi < phi0) phi0 = phi;
+    if (phi > phi1) phi1 = phi;
   }
   function linePoint(lambda, phi) {
-    var p = cartesian([lambda * radians, phi * radians]);
+    var p2 = cartesian([lambda * radians, phi * radians]);
     if (p0) {
-      var normal = cartesianCross(p0, p), equatorial = [normal[1], -normal[0], 0], inflection = cartesianCross(equatorial, normal);
+      var normal = cartesianCross(p0, p2), equatorial = [normal[1], -normal[0], 0], inflection = cartesianCross(equatorial, normal);
       cartesianNormalizeInPlace(inflection);
       inflection = spherical(inflection);
       var delta = lambda - lambda2, sign2 = delta > 0 ? 1 : -1, lambdai = inflection[0] * degrees * sign2, phii, antimeridian = abs(delta) > 180;
       if (antimeridian ^ (sign2 * lambda2 < lambdai && lambdai < sign2 * lambda)) {
         phii = inflection[1] * degrees;
-        if (phii > phi1)
-          phi1 = phii;
+        if (phii > phi1) phi1 = phii;
       } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign2 * lambda2 < lambdai && lambdai < sign2 * lambda)) {
         phii = -inflection[1] * degrees;
-        if (phii < phi0)
-          phi0 = phii;
+        if (phii < phi0) phi0 = phii;
       } else {
-        if (phi < phi0)
-          phi0 = phi;
-        if (phi > phi1)
-          phi1 = phi;
+        if (phi < phi0) phi0 = phi;
+        if (phi > phi1) phi1 = phi;
       }
       if (antimeridian) {
         if (lambda < lambda2) {
-          if (angle(lambda02, lambda) > angle(lambda02, lambda1))
-            lambda1 = lambda;
+          if (angle(lambda02, lambda) > angle(lambda02, lambda1)) lambda1 = lambda;
         } else {
-          if (angle(lambda, lambda1) > angle(lambda02, lambda1))
-            lambda02 = lambda;
+          if (angle(lambda, lambda1) > angle(lambda02, lambda1)) lambda02 = lambda;
         }
       } else {
         if (lambda1 >= lambda02) {
-          if (lambda < lambda02)
-            lambda02 = lambda;
-          if (lambda > lambda1)
-            lambda1 = lambda;
+          if (lambda < lambda02) lambda02 = lambda;
+          if (lambda > lambda1) lambda1 = lambda;
         } else {
           if (lambda > lambda2) {
-            if (angle(lambda02, lambda) > angle(lambda02, lambda1))
-              lambda1 = lambda;
+            if (angle(lambda02, lambda) > angle(lambda02, lambda1)) lambda1 = lambda;
           } else {
-            if (angle(lambda, lambda1) > angle(lambda02, lambda1))
-              lambda02 = lambda;
+            if (angle(lambda, lambda1) > angle(lambda02, lambda1)) lambda02 = lambda;
           }
         }
       }
     } else {
       ranges.push(range2 = [lambda02 = lambda, lambda1 = lambda]);
     }
-    if (phi < phi0)
-      phi0 = phi;
-    if (phi > phi1)
-      phi1 = phi;
-    p0 = p, lambda2 = lambda;
+    if (phi < phi0) phi0 = phi;
+    if (phi > phi1) phi1 = phi;
+    p0 = p2, lambda2 = lambda;
   }
   function boundsLineStart() {
     boundsStream.point = linePoint;
   function boundsRingEnd() {
     boundsRingPoint(lambda002, phi002);
     areaStream.lineEnd();
-    if (abs(deltaSum) > epsilon)
-      lambda02 = -(lambda1 = 180);
+    if (abs(deltaSum) > epsilon) lambda02 = -(lambda1 = 180);
     range2[0] = lambda02, range2[1] = lambda1;
     p0 = null;
   }
   function angle(lambda04, lambda12) {
     return (lambda12 -= lambda04) < 0 ? lambda12 + 360 : lambda12;
   }
-  function rangeCompare(a, b) {
-    return a[0] - b[0];
+  function rangeCompare(a2, b2) {
+    return a2[0] - b2[0];
   }
-  function rangeContains(range3, x) {
-    return range3[0] <= range3[1] ? range3[0] <= x && x <= range3[1] : x < range3[0] || range3[1] < x;
+  function rangeContains(range3, x2) {
+    return range3[0] <= range3[1] ? range3[0] <= x2 && x2 <= range3[1] : x2 < range3[0] || range3[1] < x2;
   }
   function bounds_default(feature3) {
-    var i2, n2, a, b, merged, deltaMax, delta;
+    var i3, n3, a2, b2, merged, deltaMax, delta;
     phi1 = lambda1 = -(lambda02 = phi0 = Infinity);
     ranges = [];
     stream_default(feature3, boundsStream);
-    if (n2 = ranges.length) {
+    if (n3 = ranges.length) {
       ranges.sort(rangeCompare);
-      for (i2 = 1, a = ranges[0], merged = [a]; i2 < n2; ++i2) {
-        b = ranges[i2];
-        if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
-          if (angle(a[0], b[1]) > angle(a[0], a[1]))
-            a[1] = b[1];
-          if (angle(b[0], a[1]) > angle(a[0], a[1]))
-            a[0] = b[0];
+      for (i3 = 1, a2 = ranges[0], merged = [a2]; i3 < n3; ++i3) {
+        b2 = ranges[i3];
+        if (rangeContains(a2, b2[0]) || rangeContains(a2, b2[1])) {
+          if (angle(a2[0], b2[1]) > angle(a2[0], a2[1])) a2[1] = b2[1];
+          if (angle(b2[0], a2[1]) > angle(a2[0], a2[1])) a2[0] = b2[0];
         } else {
-          merged.push(a = b);
+          merged.push(a2 = b2);
         }
       }
-      for (deltaMax = -Infinity, n2 = merged.length - 1, i2 = 0, a = merged[n2]; i2 <= n2; a = b, ++i2) {
-        b = merged[i2];
-        if ((delta = angle(a[1], b[0])) > deltaMax)
-          deltaMax = delta, lambda02 = b[0], lambda1 = a[1];
+      for (deltaMax = -Infinity, n3 = merged.length - 1, i3 = 0, a2 = merged[n3]; i3 <= n3; a2 = b2, ++i3) {
+        b2 = merged[i3];
+        if ((delta = angle(a2[1], b2[0])) > deltaMax) deltaMax = delta, lambda02 = b2[0], lambda1 = a2[1];
       }
     }
     ranges = range2 = null;
   }
 
   // node_modules/d3-geo/src/compose.js
-  function compose_default(a, b) {
-    function compose(x, y) {
-      return x = a(x, y), b(x[0], x[1]);
+  function compose_default(a2, b2) {
+    function compose(x2, y2) {
+      return x2 = a2(x2, y2), b2(x2[0], x2[1]);
     }
-    if (a.invert && b.invert)
-      compose.invert = function(x, y) {
-        return x = b.invert(x, y), x && a.invert(x[0], x[1]);
-      };
+    if (a2.invert && b2.invert) compose.invert = function(x2, y2) {
+      return x2 = b2.invert(x2, y2), x2 && a2.invert(x2[0], x2[1]);
+    };
     return compose;
   }
 
   function rotationPhiGamma(deltaPhi, deltaGamma) {
     var cosDeltaPhi = cos(deltaPhi), sinDeltaPhi = sin(deltaPhi), cosDeltaGamma = cos(deltaGamma), sinDeltaGamma = sin(deltaGamma);
     function rotation(lambda, phi) {
-      var cosPhi = cos(phi), x = cos(lambda) * cosPhi, y = sin(lambda) * cosPhi, z = sin(phi), k = z * cosDeltaPhi + x * sinDeltaPhi;
+      var cosPhi = cos(phi), x2 = cos(lambda) * cosPhi, y2 = sin(lambda) * cosPhi, z2 = sin(phi), k2 = z2 * cosDeltaPhi + x2 * sinDeltaPhi;
       return [
-        atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
-        asin(k * cosDeltaGamma + y * sinDeltaGamma)
+        atan2(y2 * cosDeltaGamma - k2 * sinDeltaGamma, x2 * cosDeltaPhi - z2 * sinDeltaPhi),
+        asin(k2 * cosDeltaGamma + y2 * sinDeltaGamma)
       ];
     }
     rotation.invert = function(lambda, phi) {
-      var cosPhi = cos(phi), x = cos(lambda) * cosPhi, y = sin(lambda) * cosPhi, z = sin(phi), k = z * cosDeltaGamma - y * sinDeltaGamma;
+      var cosPhi = cos(phi), x2 = cos(lambda) * cosPhi, y2 = sin(lambda) * cosPhi, z2 = sin(phi), k2 = z2 * cosDeltaGamma - y2 * sinDeltaGamma;
       return [
-        atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
-        asin(k * cosDeltaPhi - x * sinDeltaPhi)
+        atan2(y2 * cosDeltaGamma + z2 * sinDeltaGamma, x2 * cosDeltaPhi + k2 * sinDeltaPhi),
+        asin(k2 * cosDeltaPhi - x2 * sinDeltaPhi)
       ];
     };
     return rotation;
 
   // node_modules/d3-geo/src/circle.js
   function circleStream(stream, radius, delta, direction, t0, t1) {
-    if (!delta)
-      return;
+    if (!delta) return;
     var cosRadius = cos(radius), sinRadius = sin(radius), step = direction * delta;
     if (t0 == null) {
       t0 = radius + direction * tau;
     } else {
       t0 = circleRadius(cosRadius, t0);
       t1 = circleRadius(cosRadius, t1);
-      if (direction > 0 ? t0 < t1 : t0 > t1)
-        t0 += direction * tau;
+      if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
     }
-    for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
-      point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
+    for (var point, t2 = t0; direction > 0 ? t2 > t1 : t2 < t1; t2 -= step) {
+      point = spherical([cosRadius, -sinRadius * cos(t2), -sinRadius * sin(t2)]);
       stream.point(point[0], point[1]);
     }
   }
   function buffer_default() {
     var lines = [], line;
     return {
-      point: function(x, y, m) {
-        line.push([x, y, m]);
+      point: function(x2, y2, m2) {
+        line.push([x2, y2, m2]);
       },
       lineStart: function() {
         lines.push(line = []);
       },
       lineEnd: noop,
       rejoin: function() {
-        if (lines.length > 1)
-          lines.push(lines.pop().concat(lines.shift()));
+        if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
       },
       result: function() {
         var result = lines;
   }
 
   // node_modules/d3-geo/src/pointEqual.js
-  function pointEqual_default(a, b) {
-    return abs(a[0] - b[0]) < epsilon && abs(a[1] - b[1]) < epsilon;
+  function pointEqual_default(a2, b2) {
+    return abs(a2[0] - b2[0]) < epsilon && abs(a2[1] - b2[1]) < epsilon;
   }
 
   // node_modules/d3-geo/src/clip/rejoin.js
     this.n = this.p = null;
   }
   function rejoin_default(segments, compareIntersection2, startInside, interpolate, stream) {
-    var subject = [], clip = [], i2, n2;
+    var subject = [], clip = [], i3, n3;
     segments.forEach(function(segment) {
-      if ((n3 = segment.length - 1) <= 0)
-        return;
-      var n3, p02 = segment[0], p1 = segment[n3], x;
+      if ((n4 = segment.length - 1) <= 0) return;
+      var n4, p02 = segment[0], p1 = segment[n4], x2;
       if (pointEqual_default(p02, p1)) {
         if (!p02[2] && !p1[2]) {
           stream.lineStart();
-          for (i2 = 0; i2 < n3; ++i2)
-            stream.point((p02 = segment[i2])[0], p02[1]);
+          for (i3 = 0; i3 < n4; ++i3) stream.point((p02 = segment[i3])[0], p02[1]);
           stream.lineEnd();
           return;
         }
         p1[0] += 2 * epsilon;
       }
-      subject.push(x = new Intersection(p02, segment, null, true));
-      clip.push(x.o = new Intersection(p02, null, x, false));
-      subject.push(x = new Intersection(p1, segment, null, false));
-      clip.push(x.o = new Intersection(p1, null, x, true));
+      subject.push(x2 = new Intersection(p02, segment, null, true));
+      clip.push(x2.o = new Intersection(p02, null, x2, false));
+      subject.push(x2 = new Intersection(p1, segment, null, false));
+      clip.push(x2.o = new Intersection(p1, null, x2, true));
     });
-    if (!subject.length)
-      return;
+    if (!subject.length) return;
     clip.sort(compareIntersection2);
     link(subject);
     link(clip);
-    for (i2 = 0, n2 = clip.length; i2 < n2; ++i2) {
-      clip[i2].e = startInside = !startInside;
+    for (i3 = 0, n3 = clip.length; i3 < n3; ++i3) {
+      clip[i3].e = startInside = !startInside;
     }
     var start2 = subject[0], points, point;
     while (1) {
       var current = start2, isSubject = true;
-      while (current.v)
-        if ((current = current.n) === start2)
-          return;
+      while (current.v) if ((current = current.n) === start2) return;
       points = current.z;
       stream.lineStart();
       do {
         current.v = current.o.v = true;
         if (current.e) {
           if (isSubject) {
-            for (i2 = 0, n2 = points.length; i2 < n2; ++i2)
-              stream.point((point = points[i2])[0], point[1]);
+            for (i3 = 0, n3 = points.length; i3 < n3; ++i3) stream.point((point = points[i3])[0], point[1]);
           } else {
             interpolate(current.x, current.n.x, 1, stream);
           }
         } else {
           if (isSubject) {
             points = current.p.z;
-            for (i2 = points.length - 1; i2 >= 0; --i2)
-              stream.point((point = points[i2])[0], point[1]);
+            for (i3 = points.length - 1; i3 >= 0; --i3) stream.point((point = points[i3])[0], point[1]);
           } else {
             interpolate(current.x, current.p.x, -1, stream);
           }
     }
   }
   function link(array2) {
-    if (!(n2 = array2.length))
-      return;
-    var n2, i2 = 0, a = array2[0], b;
-    while (++i2 < n2) {
-      a.n = b = array2[i2];
-      b.p = a;
-      a = b;
+    if (!(n3 = array2.length)) return;
+    var n3, i3 = 0, a2 = array2[0], b2;
+    while (++i3 < n3) {
+      a2.n = b2 = array2[i3];
+      b2.p = a2;
+      a2 = b2;
     }
-    a.n = b = array2[0];
-    b.p = a;
+    a2.n = b2 = array2[0];
+    b2.p = a2;
   }
 
   // node_modules/d3-geo/src/polygonContains.js
   function polygonContains_default(polygon2, point) {
     var lambda = longitude(point), phi = point[1], sinPhi = sin(phi), normal = [sin(lambda), -cos(lambda), 0], angle2 = 0, winding = 0;
     var sum = new Adder();
-    if (sinPhi === 1)
-      phi = halfPi + epsilon;
-    else if (sinPhi === -1)
-      phi = -halfPi - epsilon;
-    for (var i2 = 0, n2 = polygon2.length; i2 < n2; ++i2) {
-      if (!(m = (ring = polygon2[i2]).length))
-        continue;
-      var ring, m, point0 = ring[m - 1], lambda04 = longitude(point0), phi02 = point0[1] / 2 + quarterPi, sinPhi03 = sin(phi02), cosPhi03 = cos(phi02);
-      for (var j2 = 0; j2 < m; ++j2, lambda04 = lambda12, sinPhi03 = sinPhi1, cosPhi03 = cosPhi1, point0 = point1) {
-        var point1 = ring[j2], lambda12 = longitude(point1), phi12 = point1[1] / 2 + quarterPi, sinPhi1 = sin(phi12), cosPhi1 = cos(phi12), delta = lambda12 - lambda04, sign2 = delta >= 0 ? 1 : -1, absDelta = sign2 * delta, antimeridian = absDelta > pi, k = sinPhi03 * sinPhi1;
-        sum.add(atan2(k * sign2 * sin(absDelta), cosPhi03 * cosPhi1 + k * cos(absDelta)));
+    if (sinPhi === 1) phi = halfPi + epsilon;
+    else if (sinPhi === -1) phi = -halfPi - epsilon;
+    for (var i3 = 0, n3 = polygon2.length; i3 < n3; ++i3) {
+      if (!(m2 = (ring = polygon2[i3]).length)) continue;
+      var ring, m2, point0 = ring[m2 - 1], lambda04 = longitude(point0), phi02 = point0[1] / 2 + quarterPi, sinPhi03 = sin(phi02), cosPhi03 = cos(phi02);
+      for (var j2 = 0; j2 < m2; ++j2, lambda04 = lambda12, sinPhi03 = sinPhi1, cosPhi03 = cosPhi1, point0 = point1) {
+        var point1 = ring[j2], lambda12 = longitude(point1), phi12 = point1[1] / 2 + quarterPi, sinPhi1 = sin(phi12), cosPhi1 = cos(phi12), delta = lambda12 - lambda04, sign2 = delta >= 0 ? 1 : -1, absDelta = sign2 * delta, antimeridian = absDelta > pi, k2 = sinPhi03 * sinPhi1;
+        sum.add(atan2(k2 * sign2 * sin(absDelta), cosPhi03 * cosPhi1 + k2 * cos(absDelta)));
         angle2 += antimeridian ? delta + sign2 * tau : delta;
         if (antimeridian ^ lambda04 >= lambda ^ lambda12 >= lambda) {
           var arc = cartesianCross(cartesian(point0), cartesian(point1));
           cartesianNormalizeInPlace(arc);
-          var intersection = cartesianCross(normal, arc);
-          cartesianNormalizeInPlace(intersection);
-          var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
+          var intersection2 = cartesianCross(normal, arc);
+          cartesianNormalizeInPlace(intersection2);
+          var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection2[2]);
           if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
             winding += antimeridian ^ delta >= 0 ? 1 : -1;
           }
           segments = merge(segments);
           var startInside = polygonContains_default(polygon2, start2);
           if (segments.length) {
-            if (!polygonStarted)
-              sink.polygonStart(), polygonStarted = true;
+            if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
             rejoin_default(segments, compareIntersection, startInside, interpolate, sink);
           } else if (startInside) {
-            if (!polygonStarted)
-              sink.polygonStart(), polygonStarted = true;
+            if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
             sink.lineStart();
             interpolate(null, null, 1, sink);
             sink.lineEnd();
           }
-          if (polygonStarted)
-            sink.polygonEnd(), polygonStarted = false;
+          if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
           segments = polygon2 = null;
         },
         sphere: function() {
         }
       };
       function point(lambda, phi) {
-        if (pointVisible(lambda, phi))
-          sink.point(lambda, phi);
+        if (pointVisible(lambda, phi)) sink.point(lambda, phi);
       }
       function pointLine(lambda, phi) {
         line.point(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(), i3, n3 = ringSegments.length, m2, segment, point2;
         ring.pop();
         polygon2.push(ring);
         ring = null;
-        if (!n2)
-          return;
+        if (!n3) return;
         if (clean2 & 1) {
           segment = ringSegments[0];
-          if ((m = segment.length - 1) > 0) {
-            if (!polygonStarted)
-              sink.polygonStart(), polygonStarted = true;
+          if ((m2 = segment.length - 1) > 0) {
+            if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
             sink.lineStart();
-            for (i2 = 0; i2 < m; ++i2)
-              sink.point((point2 = segment[i2])[0], point2[1]);
+            for (i3 = 0; i3 < m2; ++i3) sink.point((point2 = segment[i3])[0], point2[1]);
             sink.lineEnd();
           }
           return;
         }
-        if (n2 > 1 && clean2 & 2)
-          ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+        if (n3 > 1 && clean2 & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
         segments.push(ringSegments.filter(validSegment));
       }
       return clip;
   function validSegment(segment) {
     return segment.length > 1;
   }
-  function compareIntersection(a, b) {
-    return ((a = a.x)[0] < 0 ? a[1] - halfPi - epsilon : halfPi - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfPi - epsilon : halfPi - b[1]);
+  function compareIntersection(a2, b2) {
+    return ((a2 = a2.x)[0] < 0 ? a2[1] - halfPi - epsilon : halfPi - a2[1]) - ((b2 = b2.x)[0] < 0 ? b2[1] - halfPi - epsilon : halfPi - b2[1]);
   }
 
   // node_modules/d3-geo/src/clip/antimeridian.js
           stream.point(lambda12, phi02);
           clean2 = 0;
         } else if (sign0 !== sign1 && delta >= pi) {
-          if (abs(lambda04 - sign0) < epsilon)
-            lambda04 -= sign0 * epsilon;
-          if (abs(lambda12 - sign1) < epsilon)
-            lambda12 -= sign1 * epsilon;
+          if (abs(lambda04 - sign0) < epsilon) lambda04 -= sign0 * epsilon;
+          if (abs(lambda12 - sign1) < epsilon) lambda12 -= sign1 * epsilon;
           phi02 = clipAntimeridianIntersect(lambda04, phi02, lambda12, phi12);
           stream.point(sign0, phi02);
           stream.lineEnd();
           clean2 = 1;
         },
         point: function(lambda, phi) {
-          var point1 = [lambda, phi], point2, v = visible(lambda, phi), c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
-          if (!point0 && (v00 = v0 = v))
-            stream.lineStart();
-          if (v !== v0) {
+          var point1 = [lambda, phi], point2, v2 = visible(lambda, phi), c2 = smallRadius ? v2 ? 0 : code(lambda, phi) : v2 ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
+          if (!point0 && (v00 = v0 = v2)) stream.lineStart();
+          if (v2 !== v0) {
             point2 = intersect2(point0, point1);
             if (!point2 || pointEqual_default(point0, point2) || pointEqual_default(point1, point2))
               point1[2] = 1;
           }
-          if (v !== v0) {
+          if (v2 !== v0) {
             clean2 = 0;
-            if (v) {
+            if (v2) {
               stream.lineStart();
               point2 = intersect2(point1, point0);
               stream.point(point2[0], point2[1]);
               stream.lineEnd();
             }
             point0 = point2;
-          } else if (notHemisphere && point0 && smallRadius ^ v) {
-            var t;
-            if (!(c & c0) && (t = intersect2(point1, point0, true))) {
+          } else if (notHemisphere && point0 && smallRadius ^ v2) {
+            var t2;
+            if (!(c2 & c0) && (t2 = intersect2(point1, point0, true))) {
               clean2 = 0;
               if (smallRadius) {
                 stream.lineStart();
-                stream.point(t[0][0], t[0][1]);
-                stream.point(t[1][0], t[1][1]);
+                stream.point(t2[0][0], t2[0][1]);
+                stream.point(t2[1][0], t2[1][1]);
                 stream.lineEnd();
               } else {
-                stream.point(t[1][0], t[1][1]);
+                stream.point(t2[1][0], t2[1][1]);
                 stream.lineEnd();
                 stream.lineStart();
-                stream.point(t[0][0], t[0][1], 3);
+                stream.point(t2[0][0], t2[0][1], 3);
               }
             }
           }
-          if (v && (!point0 || !pointEqual_default(point0, point1))) {
+          if (v2 && (!point0 || !pointEqual_default(point0, point1))) {
             stream.point(point1[0], point1[1]);
           }
-          point0 = point1, v0 = v, c0 = c;
+          point0 = point1, v0 = v2, c0 = c2;
         },
         lineEnd: function() {
-          if (v0)
-            stream.lineEnd();
+          if (v0) stream.lineEnd();
           point0 = null;
         },
+        // Rejoin first and last segments if there were intersections and the first
+        // and last points were visible.
         clean: function() {
           return clean2 | (v00 && v0) << 1;
         }
       };
     }
-    function intersect2(a, b, two) {
-      var pa = cartesian(a), pb = cartesian(b);
-      var n1 = [1, 0, 0], n2 = cartesianCross(pa, pb), n2n2 = cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
-      if (!determinant)
-        return !two && a;
-      var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = cartesianCross(n1, n2), A = cartesianScale(n1, c1), B = cartesianScale(n2, c2);
-      cartesianAddInPlace(A, B);
-      var u = n1xn2, w = cartesianDot(A, u), uu = cartesianDot(u, u), t2 = w * w - uu * (cartesianDot(A, A) - 1);
-      if (t2 < 0)
-        return;
-      var t = sqrt(t2), q = cartesianScale(u, (-w - t) / uu);
-      cartesianAddInPlace(q, A);
-      q = spherical(q);
-      if (!two)
-        return q;
-      var lambda04 = a[0], lambda12 = b[0], phi02 = a[1], phi12 = b[1], z;
-      if (lambda12 < lambda04)
-        z = lambda04, lambda04 = lambda12, lambda12 = z;
+    function intersect2(a2, b2, two) {
+      var pa = cartesian(a2), pb = cartesian(b2);
+      var n1 = [1, 0, 0], n22 = cartesianCross(pa, pb), n2n2 = cartesianDot(n22, n22), n1n2 = n22[0], determinant = n2n2 - n1n2 * n1n2;
+      if (!determinant) return !two && a2;
+      var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = cartesianCross(n1, n22), A2 = cartesianScale(n1, c1), B2 = cartesianScale(n22, c2);
+      cartesianAddInPlace(A2, B2);
+      var u2 = n1xn2, w2 = cartesianDot(A2, u2), uu = cartesianDot(u2, u2), t2 = w2 * w2 - uu * (cartesianDot(A2, A2) - 1);
+      if (t2 < 0) return;
+      var t3 = sqrt(t2), q2 = cartesianScale(u2, (-w2 - t3) / uu);
+      cartesianAddInPlace(q2, A2);
+      q2 = spherical(q2);
+      if (!two) return q2;
+      var lambda04 = a2[0], lambda12 = b2[0], phi02 = a2[1], phi12 = b2[1], z2;
+      if (lambda12 < lambda04) z2 = lambda04, lambda04 = lambda12, lambda12 = z2;
       var delta2 = lambda12 - lambda04, polar = abs(delta2 - pi) < epsilon, meridian = polar || delta2 < epsilon;
-      if (!polar && phi12 < phi02)
-        z = phi02, phi02 = phi12, phi12 = z;
-      if (meridian ? polar ? phi02 + phi12 > 0 ^ q[1] < (abs(q[0] - lambda04) < epsilon ? phi02 : phi12) : phi02 <= q[1] && q[1] <= phi12 : delta2 > pi ^ (lambda04 <= q[0] && q[0] <= lambda12)) {
-        var q1 = cartesianScale(u, (-w + t) / uu);
-        cartesianAddInPlace(q1, A);
-        return [q, spherical(q1)];
+      if (!polar && phi12 < phi02) z2 = phi02, phi02 = phi12, phi12 = z2;
+      if (meridian ? polar ? phi02 + phi12 > 0 ^ q2[1] < (abs(q2[0] - lambda04) < epsilon ? phi02 : phi12) : phi02 <= q2[1] && q2[1] <= phi12 : delta2 > pi ^ (lambda04 <= q2[0] && q2[0] <= lambda12)) {
+        var q1 = cartesianScale(u2, (-w2 + t3) / uu);
+        cartesianAddInPlace(q1, A2);
+        return [q2, spherical(q1)];
       }
     }
     function code(lambda, phi) {
-      var r = smallRadius ? radius : pi - radius, code2 = 0;
-      if (lambda < -r)
-        code2 |= 1;
-      else if (lambda > r)
-        code2 |= 2;
-      if (phi < -r)
-        code2 |= 4;
-      else if (phi > r)
-        code2 |= 8;
+      var r2 = smallRadius ? radius : pi - radius, code2 = 0;
+      if (lambda < -r2) code2 |= 1;
+      else if (lambda > r2) code2 |= 2;
+      if (phi < -r2) code2 |= 4;
+      else if (phi > r2) code2 |= 8;
       return code2;
     }
     return clip_default(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
   }
 
   // node_modules/d3-geo/src/clip/line.js
-  function line_default(a, b, x05, y05, x12, y12) {
-    var ax = a[0], ay = a[1], bx = b[0], by = b[1], t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r;
-    r = x05 - ax;
-    if (!dx && r > 0)
-      return;
-    r /= dx;
+  function line_default(a2, b2, x05, y05, x12, y12) {
+    var ax = a2[0], ay = a2[1], bx = b2[0], by = b2[1], t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r2;
+    r2 = x05 - ax;
+    if (!dx && r2 > 0) return;
+    r2 /= dx;
     if (dx < 0) {
-      if (r < t0)
-        return;
-      if (r < t1)
-        t1 = r;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     } else if (dx > 0) {
-      if (r > t1)
-        return;
-      if (r > t0)
-        t0 = r;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     }
-    r = x12 - ax;
-    if (!dx && r < 0)
-      return;
-    r /= dx;
+    r2 = x12 - ax;
+    if (!dx && r2 < 0) return;
+    r2 /= dx;
     if (dx < 0) {
-      if (r > t1)
-        return;
-      if (r > t0)
-        t0 = r;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     } else if (dx > 0) {
-      if (r < t0)
-        return;
-      if (r < t1)
-        t1 = r;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     }
-    r = y05 - ay;
-    if (!dy && r > 0)
-      return;
-    r /= dy;
+    r2 = y05 - ay;
+    if (!dy && r2 > 0) return;
+    r2 /= dy;
     if (dy < 0) {
-      if (r < t0)
-        return;
-      if (r < t1)
-        t1 = r;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     } else if (dy > 0) {
-      if (r > t1)
-        return;
-      if (r > t0)
-        t0 = r;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     }
-    r = y12 - ay;
-    if (!dy && r < 0)
-      return;
-    r /= dy;
+    r2 = y12 - ay;
+    if (!dy && r2 < 0) return;
+    r2 /= dy;
     if (dy < 0) {
-      if (r > t1)
-        return;
-      if (r > t0)
-        t0 = r;
+      if (r2 > t1) return;
+      if (r2 > t0) t0 = r2;
     } else if (dy > 0) {
-      if (r < t0)
-        return;
-      if (r < t1)
-        t1 = r;
+      if (r2 < t0) return;
+      if (r2 < t1) t1 = r2;
     }
-    if (t0 > 0)
-      a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
-    if (t1 < 1)
-      b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
+    if (t0 > 0) a2[0] = ax + t0 * dx, a2[1] = ay + t0 * dy;
+    if (t1 < 1) b2[0] = ax + t1 * dx, b2[1] = ay + t1 * dy;
     return true;
   }
 
   var clipMax = 1e9;
   var clipMin = -clipMax;
   function clipRectangle(x05, y05, x12, y12) {
-    function visible(x, y) {
-      return x05 <= x && x <= x12 && y05 <= y && y <= y12;
+    function visible(x2, y2) {
+      return x05 <= x2 && x2 <= x12 && y05 <= y2 && y2 <= y12;
     }
     function interpolate(from, to, direction, stream) {
-      var a = 0, a1 = 0;
-      if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
+      var a2 = 0, a1 = 0;
+      if (from == null || (a2 = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
         do
-          stream.point(a === 0 || a === 3 ? x05 : x12, a > 1 ? y12 : y05);
-        while ((a = (a + direction + 4) % 4) !== a1);
+          stream.point(a2 === 0 || a2 === 3 ? x05 : x12, a2 > 1 ? y12 : y05);
+        while ((a2 = (a2 + direction + 4) % 4) !== a1);
       } else {
         stream.point(to[0], to[1]);
       }
     }
-    function corner(p, direction) {
-      return abs(p[0] - x05) < epsilon ? direction > 0 ? 0 : 3 : abs(p[0] - x12) < epsilon ? direction > 0 ? 2 : 1 : abs(p[1] - y05) < epsilon ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;
+    function corner(p2, direction) {
+      return abs(p2[0] - x05) < epsilon ? direction > 0 ? 0 : 3 : abs(p2[0] - x12) < epsilon ? direction > 0 ? 2 : 1 : abs(p2[1] - y05) < epsilon ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;
     }
-    function compareIntersection2(a, b) {
-      return comparePoint(a.x, b.x);
+    function compareIntersection2(a2, b2) {
+      return comparePoint(a2.x, b2.x);
     }
-    function comparePoint(a, b) {
-      var ca = corner(a, 1), cb = corner(b, 1);
-      return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];
+    function comparePoint(a2, b2) {
+      var ca = corner(a2, 1), cb = corner(b2, 1);
+      return ca !== cb ? ca - cb : ca === 0 ? b2[1] - a2[1] : ca === 1 ? a2[0] - b2[0] : ca === 2 ? a2[1] - b2[1] : b2[0] - a2[0];
     }
     return function(stream) {
       var activeStream = stream, bufferStream = buffer_default(), segments, polygon2, ring, x__, y__, v__, x_, y_, v_, first, clean2;
         polygonStart,
         polygonEnd
       };
-      function point(x, y) {
-        if (visible(x, y))
-          activeStream.point(x, y);
+      function point(x2, y2) {
+        if (visible(x2, y2)) activeStream.point(x2, y2);
       }
       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) {
+        for (var i3 = 0, n3 = polygon2.length; i3 < n3; ++i3) {
+          for (var ring2 = polygon2[i3], j2 = 1, m2 = ring2.length, point2 = ring2[0], a0, a1, b0 = point2[0], b1 = point2[1]; j2 < m2; ++j2) {
             a0 = b0, a1 = b1, point2 = ring2[j2], b0 = point2[0], b1 = point2[1];
             if (a1 <= y12) {
-              if (b1 > y12 && (b0 - a0) * (y12 - a1) > (b1 - a1) * (x05 - a0))
-                ++winding;
+              if (b1 > y12 && (b0 - a0) * (y12 - a1) > (b1 - a1) * (x05 - a0)) ++winding;
             } else {
-              if (b1 <= y12 && (b0 - a0) * (y12 - a1) < (b1 - a1) * (x05 - a0))
-                --winding;
+              if (b1 <= y12 && (b0 - a0) * (y12 - a1) < (b1 - a1) * (x05 - a0)) --winding;
             }
           }
         }
       }
       function lineStart() {
         clipStream.point = linePoint2;
-        if (polygon2)
-          polygon2.push(ring = []);
+        if (polygon2) polygon2.push(ring = []);
         first = true;
         v_ = false;
         x_ = y_ = NaN;
       function lineEnd() {
         if (segments) {
           linePoint2(x__, y__);
-          if (v__ && v_)
-            bufferStream.rejoin();
+          if (v__ && v_) bufferStream.rejoin();
           segments.push(bufferStream.result());
         }
         clipStream.point = point;
-        if (v_)
-          activeStream.lineEnd();
+        if (v_) activeStream.lineEnd();
       }
-      function linePoint2(x, y) {
-        var v = visible(x, y);
-        if (polygon2)
-          ring.push([x, y]);
+      function linePoint2(x2, y2) {
+        var v2 = visible(x2, y2);
+        if (polygon2) ring.push([x2, y2]);
         if (first) {
-          x__ = x, y__ = y, v__ = v;
+          x__ = x2, y__ = y2, v__ = v2;
           first = false;
-          if (v) {
+          if (v2) {
             activeStream.lineStart();
-            activeStream.point(x, y);
+            activeStream.point(x2, y2);
           }
         } else {
-          if (v && v_)
-            activeStream.point(x, y);
+          if (v2 && v_) activeStream.point(x2, y2);
           else {
-            var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))], b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
-            if (line_default(a, b, x05, y05, x12, y12)) {
+            var a2 = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))], b2 = [x2 = Math.max(clipMin, Math.min(clipMax, x2)), y2 = Math.max(clipMin, Math.min(clipMax, y2))];
+            if (line_default(a2, b2, x05, y05, x12, y12)) {
               if (!v_) {
                 activeStream.lineStart();
-                activeStream.point(a[0], a[1]);
+                activeStream.point(a2[0], a2[1]);
               }
-              activeStream.point(b[0], b[1]);
-              if (!v)
-                activeStream.lineEnd();
+              activeStream.point(b2[0], b2[1]);
+              if (!v2) activeStream.lineEnd();
               clean2 = false;
-            } else if (v) {
+            } else if (v2) {
               activeStream.lineStart();
-              activeStream.point(x, y);
+              activeStream.point(x2, y2);
               clean2 = false;
             }
           }
         }
-        x_ = x, y_ = y, v_ = v;
+        x_ = x2, y_ = y2, v_ = v2;
       }
       return clipStream;
     };
   }
   function lengthPoint(lambda, phi) {
     lambda *= radians, phi *= radians;
-    var sinPhi = sin(phi), cosPhi = cos(phi), delta = abs(lambda - lambda03), cosDelta = cos(delta), sinDelta = sin(delta), x = cosPhi * sinDelta, y = cosPhi02 * sinPhi - sinPhi02 * cosPhi * cosDelta, z = sinPhi02 * sinPhi + cosPhi02 * cosPhi * cosDelta;
-    lengthSum.add(atan2(sqrt(x * x + y * y), z));
+    var sinPhi = sin(phi), cosPhi = cos(phi), delta = abs(lambda - lambda03), cosDelta = cos(delta), sinDelta = sin(delta), x2 = cosPhi * sinDelta, y2 = cosPhi02 * sinPhi - sinPhi02 * cosPhi * cosDelta, z2 = sinPhi02 * sinPhi + cosPhi02 * cosPhi * cosDelta;
+    lengthSum.add(atan2(sqrt(x2 * x2 + y2 * y2), z2));
     lambda03 = lambda, sinPhi02 = sinPhi, cosPhi02 = cosPhi;
   }
   function length_default(object) {
   }
 
   // node_modules/d3-geo/src/identity.js
-  var identity_default = (x) => x;
+  var identity_default = (x2) => x2;
 
   // node_modules/d3-geo/src/path/area.js
   var areaSum2 = new Adder();
   function areaRingStart2() {
     areaStream2.point = areaPointFirst2;
   }
-  function areaPointFirst2(x, y) {
+  function areaPointFirst2(x2, y2) {
     areaStream2.point = areaPoint2;
-    x00 = x0 = x, y00 = y0 = y;
+    x00 = x0 = x2, y00 = y0 = y2;
   }
-  function areaPoint2(x, y) {
-    areaRingSum2.add(y0 * x - x0 * y);
-    x0 = x, y0 = y;
+  function areaPoint2(x2, y2) {
+    areaRingSum2.add(y0 * x2 - x0 * y2);
+    x0 = x2, y0 = y2;
   }
   function areaRingEnd2() {
     areaPoint2(x00, y00);
       return bounds;
     }
   };
-  function boundsPoint2(x, y) {
-    if (x < x02)
-      x02 = x;
-    if (x > x1)
-      x1 = x;
-    if (y < y02)
-      y02 = y;
-    if (y > y1)
-      y1 = y;
+  function boundsPoint2(x2, y2) {
+    if (x2 < x02) x02 = x2;
+    if (x2 > x1) x1 = x2;
+    if (y2 < y02) y02 = y2;
+    if (y2 > y1) y1 = y2;
   }
   var bounds_default2 = boundsStream2;
 
       return centroid;
     }
   };
-  function centroidPoint(x, y) {
-    X0 += x;
-    Y0 += y;
+  function centroidPoint(x2, y2) {
+    X0 += x2;
+    Y0 += y2;
     ++Z0;
   }
   function centroidLineStart() {
     centroidStream.point = centroidPointFirstLine;
   }
-  function centroidPointFirstLine(x, y) {
+  function centroidPointFirstLine(x2, y2) {
     centroidStream.point = centroidPointLine;
-    centroidPoint(x03 = x, y03 = y);
+    centroidPoint(x03 = x2, y03 = y2);
   }
-  function centroidPointLine(x, y) {
-    var dx = x - x03, dy = y - y03, z = sqrt(dx * dx + dy * dy);
-    X1 += z * (x03 + x) / 2;
-    Y1 += z * (y03 + y) / 2;
-    Z1 += z;
-    centroidPoint(x03 = x, y03 = y);
+  function centroidPointLine(x2, y2) {
+    var dx = x2 - x03, dy = y2 - y03, z2 = sqrt(dx * dx + dy * dy);
+    X1 += z2 * (x03 + x2) / 2;
+    Y1 += z2 * (y03 + y2) / 2;
+    Z1 += z2;
+    centroidPoint(x03 = x2, y03 = y2);
   }
   function centroidLineEnd() {
     centroidStream.point = centroidPoint;
   function centroidRingEnd() {
     centroidPointRing(x002, y002);
   }
-  function centroidPointFirstRing(x, y) {
+  function centroidPointFirstRing(x2, y2) {
     centroidStream.point = centroidPointRing;
-    centroidPoint(x002 = x03 = x, y002 = y03 = y);
-  }
-  function centroidPointRing(x, y) {
-    var dx = x - x03, dy = y - y03, z = sqrt(dx * dx + dy * dy);
-    X1 += z * (x03 + x) / 2;
-    Y1 += z * (y03 + y) / 2;
-    Z1 += z;
-    z = y03 * x - x03 * y;
-    X2 += z * (x03 + x);
-    Y2 += z * (y03 + y);
-    Z2 += z * 3;
-    centroidPoint(x03 = x, y03 = y);
+    centroidPoint(x002 = x03 = x2, y002 = y03 = y2);
+  }
+  function centroidPointRing(x2, y2) {
+    var dx = x2 - x03, dy = y2 - y03, z2 = sqrt(dx * dx + dy * dy);
+    X1 += z2 * (x03 + x2) / 2;
+    Y1 += z2 * (y03 + y2) / 2;
+    Z1 += z2;
+    z2 = y03 * x2 - x03 * y2;
+    X2 += z2 * (x03 + x2);
+    Y2 += z2 * (y03 + y2);
+    Z2 += z2 * 3;
+    centroidPoint(x03 = x2, y03 = y2);
   }
   var centroid_default = centroidStream;
 
   }
   PathContext.prototype = {
     _radius: 4.5,
-    pointRadius: function(_) {
-      return this._radius = _, this;
+    pointRadius: function(_2) {
+      return this._radius = _2, this;
     },
     polygonStart: function() {
       this._line = 0;
       this._point = 0;
     },
     lineEnd: function() {
-      if (this._line === 0)
-        this._context.closePath();
+      if (this._line === 0) this._context.closePath();
       this._point = NaN;
     },
-    point: function(x, y) {
+    point: function(x2, y2) {
       switch (this._point) {
         case 0: {
-          this._context.moveTo(x, y);
+          this._context.moveTo(x2, y2);
           this._point = 1;
           break;
         }
         case 1: {
-          this._context.lineTo(x, y);
+          this._context.lineTo(x2, y2);
           break;
         }
         default: {
-          this._context.moveTo(x + this._radius, y);
-          this._context.arc(x, y, this._radius, 0, tau);
+          this._context.moveTo(x2 + this._radius, y2);
+          this._context.arc(x2, y2, this._radius, 0, tau);
           break;
         }
       }
       lengthStream2.point = lengthPointFirst2;
     },
     lineEnd: function() {
-      if (lengthRing)
-        lengthPoint2(x003, y003);
+      if (lengthRing) lengthPoint2(x003, y003);
       lengthStream2.point = noop;
     },
     polygonStart: function() {
       lengthRing = null;
     },
     result: function() {
-      var length = +lengthSum2;
+      var length2 = +lengthSum2;
       lengthSum2 = new Adder();
-      return length;
+      return length2;
     }
   };
-  function lengthPointFirst2(x, y) {
+  function lengthPointFirst2(x2, y2) {
     lengthStream2.point = lengthPoint2;
-    x003 = x04 = x, y003 = y04 = y;
+    x003 = x04 = x2, y003 = y04 = y2;
   }
-  function lengthPoint2(x, y) {
-    x04 -= x, y04 -= y;
+  function lengthPoint2(x2, y2) {
+    x04 -= x2, y04 -= y2;
     lengthSum2.add(sqrt(x04 * x04 + y04 * y04));
-    x04 = x, y04 = y;
+    x04 = x2, y04 = y2;
   }
   var measure_default = lengthStream2;
 
   PathString.prototype = {
     _radius: 4.5,
     _circle: circle(4.5),
-    pointRadius: function(_) {
-      if ((_ = +_) !== this._radius)
-        this._radius = _, this._circle = null;
+    pointRadius: function(_2) {
+      if ((_2 = +_2) !== this._radius) this._radius = _2, this._circle = null;
       return this;
     },
     polygonStart: function() {
       this._point = 0;
     },
     lineEnd: function() {
-      if (this._line === 0)
-        this._string.push("Z");
+      if (this._line === 0) this._string.push("Z");
       this._point = NaN;
     },
-    point: function(x, y) {
+    point: function(x2, y2) {
       switch (this._point) {
         case 0: {
-          this._string.push("M", x, ",", y);
+          this._string.push("M", x2, ",", y2);
           this._point = 1;
           break;
         }
         case 1: {
-          this._string.push("L", x, ",", y);
+          this._string.push("L", x2, ",", y2);
           break;
         }
         default: {
-          if (this._circle == null)
-            this._circle = circle(this._radius);
-          this._string.push("M", x, ",", y, this._circle);
+          if (this._circle == null) this._circle = circle(this._radius);
+          this._string.push("M", x2, ",", y2, this._circle);
           break;
         }
       }
     var pointRadius = 4.5, projectionStream, contextStream;
     function path(object) {
       if (object) {
-        if (typeof pointRadius === "function")
-          contextStream.pointRadius(+pointRadius.apply(this, arguments));
+        if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
         stream_default(object, projectionStream(contextStream));
       }
       return contextStream.result();
       stream_default(object, projectionStream(centroid_default));
       return centroid_default.result();
     };
-    path.projection = function(_) {
-      return arguments.length ? (projectionStream = _ == null ? (projection2 = null, identity_default) : (projection2 = _).stream, path) : projection2;
+    path.projection = function(_2) {
+      return arguments.length ? (projectionStream = _2 == null ? (projection2 = null, identity_default) : (projection2 = _2).stream, path) : projection2;
     };
-    path.context = function(_) {
-      if (!arguments.length)
-        return context;
-      contextStream = _ == null ? (context = null, new PathString()) : new PathContext(context = _);
-      if (typeof pointRadius !== "function")
-        contextStream.pointRadius(pointRadius);
+    path.context = function(_2) {
+      if (!arguments.length) return context;
+      contextStream = _2 == null ? (context = null, new PathString()) : new PathContext(context = _2);
+      if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
       return path;
     };
-    path.pointRadius = function(_) {
-      if (!arguments.length)
-        return pointRadius;
-      pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
+    path.pointRadius = function(_2) {
+      if (!arguments.length) return pointRadius;
+      pointRadius = typeof _2 === "function" ? _2 : (contextStream.pointRadius(+_2), +_2);
       return path;
     };
     return path.projection(projection2).context(context);
   }
   function transformer(methods2) {
     return function(stream) {
-      var s = new TransformStream();
-      for (var key in methods2)
-        s[key] = methods2[key];
-      s.stream = stream;
-      return s;
+      var s2 = new TransformStream();
+      for (var key in methods2) s2[key] = methods2[key];
+      s2.stream = stream;
+      return s2;
     };
   }
   function TransformStream() {
   }
   TransformStream.prototype = {
     constructor: TransformStream,
-    point: function(x, y) {
-      this.stream.point(x, y);
+    point: function(x2, y2) {
+      this.stream.point(x2, y2);
     },
     sphere: function() {
       this.stream.sphere();
   function fit(projection2, fitBounds, object) {
     var clip = projection2.clipExtent && projection2.clipExtent();
     projection2.scale(150).translate([0, 0]);
-    if (clip != null)
-      projection2.clipExtent(null);
+    if (clip != null) projection2.clipExtent(null);
     stream_default(object, projection2.stream(bounds_default2));
     fitBounds(bounds_default2.result());
-    if (clip != null)
-      projection2.clipExtent(clip);
+    if (clip != null) projection2.clipExtent(clip);
     return projection2;
   }
   function fitExtent(projection2, extent, object) {
-    return fit(projection2, function(b) {
-      var w = extent[1][0] - extent[0][0], h = extent[1][1] - extent[0][1], k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])), x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2, y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
-      projection2.scale(150 * k).translate([x, y]);
+    return fit(projection2, function(b2) {
+      var w2 = extent[1][0] - extent[0][0], h2 = extent[1][1] - extent[0][1], k2 = Math.min(w2 / (b2[1][0] - b2[0][0]), h2 / (b2[1][1] - b2[0][1])), x2 = +extent[0][0] + (w2 - k2 * (b2[1][0] + b2[0][0])) / 2, y2 = +extent[0][1] + (h2 - k2 * (b2[1][1] + b2[0][1])) / 2;
+      projection2.scale(150 * k2).translate([x2, y2]);
     }, object);
   }
   function fitSize(projection2, size, object) {
     return fitExtent(projection2, [[0, 0], size], object);
   }
   function fitWidth(projection2, width, object) {
-    return fit(projection2, function(b) {
-      var w = +width, k = w / (b[1][0] - b[0][0]), x = (w - k * (b[1][0] + b[0][0])) / 2, y = -k * b[0][1];
-      projection2.scale(150 * k).translate([x, y]);
+    return fit(projection2, function(b2) {
+      var w2 = +width, k2 = w2 / (b2[1][0] - b2[0][0]), x2 = (w2 - k2 * (b2[1][0] + b2[0][0])) / 2, y2 = -k2 * b2[0][1];
+      projection2.scale(150 * k2).translate([x2, y2]);
     }, object);
   }
   function fitHeight(projection2, height, object) {
-    return fit(projection2, function(b) {
-      var h = +height, k = h / (b[1][1] - b[0][1]), x = -k * b[0][0], y = (h - k * (b[1][1] + b[0][1])) / 2;
-      projection2.scale(150 * k).translate([x, y]);
+    return fit(projection2, function(b2) {
+      var h2 = +height, k2 = h2 / (b2[1][1] - b2[0][1]), x2 = -k2 * b2[0][0], y2 = (h2 - k2 * (b2[1][1] + b2[0][1])) / 2;
+      projection2.scale(150 * k2).translate([x2, y2]);
     }, object);
   }
 
   }
   function resampleNone(project) {
     return transformer({
-      point: function(x, y) {
-        x = project(x, y);
-        this.stream.point(x[0], x[1]);
+      point: function(x2, y2) {
+        x2 = project(x2, y2);
+        this.stream.point(x2[0], x2[1]);
       }
     });
   }
     function resampleLineTo(x05, y05, lambda04, a0, b0, c0, x12, y12, lambda12, a1, b1, c1, depth, stream) {
       var dx = x12 - x05, dy = y12 - y05, d2 = dx * dx + dy * dy;
       if (d2 > 4 * delta2 && depth--) {
-        var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = sqrt(a * a + b * b + c * c), phi2 = asin(c /= m), lambda22 = abs(abs(c) - 1) < epsilon || abs(lambda04 - lambda12) < epsilon ? (lambda04 + lambda12) / 2 : atan2(b, a), p = project(lambda22, phi2), x2 = p[0], y2 = p[1], dx2 = x2 - x05, dy2 = y2 - y05, dz = dy * dx2 - dx * dy2;
+        var a2 = a0 + a1, b2 = b0 + b1, c2 = c0 + c1, m2 = sqrt(a2 * a2 + b2 * b2 + c2 * c2), phi2 = asin(c2 /= m2), lambda22 = abs(abs(c2) - 1) < epsilon || abs(lambda04 - lambda12) < epsilon ? (lambda04 + lambda12) / 2 : atan2(b2, a2), p2 = project(lambda22, phi2), x2 = p2[0], y2 = p2[1], dx2 = x2 - x05, dy2 = y2 - y05, dz = dy * dx2 - dx * dy2;
         if (dz * dz / d2 > delta2 || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
-          resampleLineTo(x05, y05, lambda04, a0, b0, c0, x2, y2, lambda22, a /= m, b /= m, c, depth, stream);
+          resampleLineTo(x05, y05, lambda04, a0, b0, c0, x2, y2, lambda22, a2 /= m2, b2 /= m2, c2, depth, stream);
           stream.point(x2, y2);
-          resampleLineTo(x2, y2, lambda22, a, b, c, x12, y12, lambda12, a1, b1, c1, depth, stream);
+          resampleLineTo(x2, y2, lambda22, a2, b2, c2, x12, y12, lambda12, a1, b1, c1, depth, stream);
         }
       }
     }
           resampleStream.lineStart = lineStart;
         }
       };
-      function point(x, y) {
-        x = project(x, y);
-        stream.point(x[0], x[1]);
+      function point(x2, y2) {
+        x2 = project(x2, y2);
+        stream.point(x2[0], x2[1]);
       }
       function lineStart() {
         x05 = NaN;
         stream.lineStart();
       }
       function linePoint2(lambda, phi) {
-        var c = cartesian([lambda, phi]), p = project(lambda, phi);
-        resampleLineTo(x05, y05, lambda04, a0, b0, c0, x05 = p[0], y05 = p[1], lambda04 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
+        var c2 = cartesian([lambda, phi]), p2 = project(lambda, phi);
+        resampleLineTo(x05, y05, lambda04, a0, b0, c0, x05 = p2[0], y05 = p2[1], lambda04 = lambda, a0 = c2[0], b0 = c2[1], c0 = c2[2], maxDepth, stream);
         stream.point(x05, y05);
       }
       function lineEnd() {
 
   // node_modules/d3-geo/src/projection/index.js
   var transformRadians = transformer({
-    point: function(x, y) {
-      this.stream.point(x * radians, y * radians);
+    point: function(x2, y2) {
+      this.stream.point(x2 * radians, y2 * radians);
     }
   });
   function transformRotate(rotate) {
     return transformer({
-      point: function(x, y) {
-        var r = rotate(x, y);
-        return this.stream.point(r[0], r[1]);
+      point: function(x2, y2) {
+        var r2 = rotate(x2, y2);
+        return this.stream.point(r2[0], r2[1]);
       }
     });
   }
-  function scaleTranslate(k, dx, dy, sx, sy) {
-    function transform2(x, y) {
-      x *= sx;
-      y *= sy;
-      return [dx + k * x, dy - k * y];
+  function scaleTranslate(k2, dx, dy, sx, sy) {
+    function transform2(x2, y2) {
+      x2 *= sx;
+      y2 *= sy;
+      return [dx + k2 * x2, dy - k2 * y2];
     }
-    transform2.invert = function(x, y) {
-      return [(x - dx) / k * sx, (dy - y) / k * sy];
+    transform2.invert = function(x2, y2) {
+      return [(x2 - dx) / k2 * sx, (dy - y2) / k2 * sy];
     };
     return transform2;
   }
-  function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
-    if (!alpha)
-      return scaleTranslate(k, dx, dy, sx, sy);
-    var cosAlpha = cos(alpha), sinAlpha = sin(alpha), a = cosAlpha * k, b = sinAlpha * k, ai = cosAlpha / k, bi = sinAlpha / k, ci = (sinAlpha * dy - cosAlpha * dx) / k, fi = (sinAlpha * dx + cosAlpha * dy) / k;
-    function transform2(x, y) {
-      x *= sx;
-      y *= sy;
-      return [a * x - b * y + dx, dy - b * x - a * y];
+  function scaleTranslateRotate(k2, dx, dy, sx, sy, alpha) {
+    if (!alpha) return scaleTranslate(k2, dx, dy, sx, sy);
+    var cosAlpha = cos(alpha), sinAlpha = sin(alpha), a2 = cosAlpha * k2, b2 = sinAlpha * k2, ai = cosAlpha / k2, bi = sinAlpha / k2, ci = (sinAlpha * dy - cosAlpha * dx) / k2, fi = (sinAlpha * dx + cosAlpha * dy) / k2;
+    function transform2(x2, y2) {
+      x2 *= sx;
+      y2 *= sy;
+      return [a2 * x2 - b2 * y2 + dx, dy - b2 * x2 - a2 * y2];
     }
-    transform2.invert = function(x, y) {
-      return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
+    transform2.invert = function(x2, y2) {
+      return [sx * (ai * x2 - bi * y2 + ci), sy * (fi - bi * x2 - ai * y2)];
     };
     return transform2;
   }
     })();
   }
   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;
+    var project, k2 = 150, x2 = 480, y2 = 250, lambda = 0, phi = 0, deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, alpha = 0, sx = 1, sy = 1, theta = null, preclip = antimeridian_default, x05 = null, y05, x12, y12, postclip = identity_default, delta2 = 0.5, projectResample, projectTransform, projectRotateTransform, cache, cacheStream;
     function projection2(point) {
       return projectRotateTransform(point[0] * radians, point[1] * radians);
     }
     projection2.stream = function(stream) {
       return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
     };
-    projection2.preclip = function(_) {
-      return arguments.length ? (preclip = _, theta = void 0, reset()) : preclip;
+    projection2.preclip = function(_2) {
+      return arguments.length ? (preclip = _2, theta = void 0, reset()) : preclip;
     };
-    projection2.postclip = function(_) {
-      return arguments.length ? (postclip = _, x05 = y05 = x12 = y12 = null, reset()) : postclip;
+    projection2.postclip = function(_2) {
+      return arguments.length ? (postclip = _2, x05 = y05 = x12 = y12 = null, reset()) : postclip;
     };
-    projection2.clipAngle = function(_) {
-      return arguments.length ? (preclip = +_ ? circle_default(theta = _ * radians) : (theta = null, antimeridian_default), reset()) : theta * degrees;
+    projection2.clipAngle = function(_2) {
+      return arguments.length ? (preclip = +_2 ? circle_default(theta = _2 * radians) : (theta = null, antimeridian_default), reset()) : theta * degrees;
     };
-    projection2.clipExtent = function(_) {
-      return arguments.length ? (postclip = _ == null ? (x05 = y05 = x12 = y12 = null, identity_default) : clipRectangle(x05 = +_[0][0], y05 = +_[0][1], x12 = +_[1][0], y12 = +_[1][1]), reset()) : x05 == null ? null : [[x05, y05], [x12, y12]];
+    projection2.clipExtent = function(_2) {
+      return arguments.length ? (postclip = _2 == null ? (x05 = y05 = x12 = y12 = null, identity_default) : clipRectangle(x05 = +_2[0][0], y05 = +_2[0][1], x12 = +_2[1][0], y12 = +_2[1][1]), reset()) : x05 == null ? null : [[x05, y05], [x12, y12]];
     };
-    projection2.scale = function(_) {
-      return arguments.length ? (k = +_, recenter()) : k;
+    projection2.scale = function(_2) {
+      return arguments.length ? (k2 = +_2, recenter()) : k2;
     };
-    projection2.translate = function(_) {
-      return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
+    projection2.translate = function(_2) {
+      return arguments.length ? (x2 = +_2[0], y2 = +_2[1], recenter()) : [x2, y2];
     };
-    projection2.center = function(_) {
-      return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
+    projection2.center = function(_2) {
+      return arguments.length ? (lambda = _2[0] % 360 * radians, phi = _2[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
     };
-    projection2.rotate = function(_) {
-      return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees];
+    projection2.rotate = function(_2) {
+      return arguments.length ? (deltaLambda = _2[0] % 360 * radians, deltaPhi = _2[1] % 360 * radians, deltaGamma = _2.length > 2 ? _2[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees];
     };
-    projection2.angle = function(_) {
-      return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees;
+    projection2.angle = function(_2) {
+      return arguments.length ? (alpha = _2 % 360 * radians, recenter()) : alpha * degrees;
     };
-    projection2.reflectX = function(_) {
-      return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
+    projection2.reflectX = function(_2) {
+      return arguments.length ? (sx = _2 ? -1 : 1, recenter()) : sx < 0;
     };
-    projection2.reflectY = function(_) {
-      return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
+    projection2.reflectY = function(_2) {
+      return arguments.length ? (sy = _2 ? -1 : 1, recenter()) : sy < 0;
     };
-    projection2.precision = function(_) {
-      return arguments.length ? (projectResample = resample_default(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
+    projection2.precision = function(_2) {
+      return arguments.length ? (projectResample = resample_default(projectTransform, delta2 = _2 * _2), reset()) : sqrt(delta2);
     };
     projection2.fitExtent = function(extent, object) {
       return fitExtent(projection2, extent, object);
       return fitHeight(projection2, height, object);
     };
     function recenter() {
-      var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)), transform2 = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
+      var center = scaleTranslateRotate(k2, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)), transform2 = scaleTranslateRotate(k2, x2 - center[0], y2 - center[1], sx, sy, alpha);
       rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
       projectTransform = compose_default(project, transform2);
       projectRotateTransform = compose_default(rotate, projectTransform);
   function mercatorRaw(lambda, phi) {
     return [lambda, log(tan((halfPi + phi) / 2))];
   }
-  mercatorRaw.invert = function(x, y) {
-    return [x, 2 * atan(exp(y)) - halfPi];
+  mercatorRaw.invert = function(x2, y2) {
+    return [x2, 2 * atan(exp(y2)) - halfPi];
   };
   function mercator_default() {
     return mercatorProjection(mercatorRaw).scale(961 / tau);
   }
   function mercatorProjection(project) {
-    var m = projection(project), center = m.center, scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, x05 = null, y05, x12, y12;
-    m.scale = function(_) {
-      return arguments.length ? (scale(_), reclip()) : scale();
+    var m2 = projection(project), center = m2.center, scale = m2.scale, translate = m2.translate, clipExtent = m2.clipExtent, x05 = null, y05, x12, y12;
+    m2.scale = function(_2) {
+      return arguments.length ? (scale(_2), reclip()) : scale();
     };
-    m.translate = function(_) {
-      return arguments.length ? (translate(_), reclip()) : translate();
+    m2.translate = function(_2) {
+      return arguments.length ? (translate(_2), reclip()) : translate();
     };
-    m.center = function(_) {
-      return arguments.length ? (center(_), reclip()) : center();
+    m2.center = function(_2) {
+      return arguments.length ? (center(_2), reclip()) : center();
     };
-    m.clipExtent = function(_) {
-      return arguments.length ? (_ == null ? x05 = y05 = x12 = y12 = null : (x05 = +_[0][0], y05 = +_[0][1], x12 = +_[1][0], y12 = +_[1][1]), reclip()) : x05 == null ? null : [[x05, y05], [x12, y12]];
+    m2.clipExtent = function(_2) {
+      return arguments.length ? (_2 == null ? x05 = y05 = x12 = y12 = null : (x05 = +_2[0][0], y05 = +_2[0][1], x12 = +_2[1][0], y12 = +_2[1][1]), reclip()) : x05 == null ? null : [[x05, y05], [x12, y12]];
     };
     function reclip() {
-      var k = pi * scale(), t = m(rotation_default(m.rotate()).invert([0, 0]));
-      return clipExtent(x05 == null ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw ? [[Math.max(t[0] - k, x05), y05], [Math.min(t[0] + k, x12), y12]] : [[x05, Math.max(t[1] - k, y05)], [x12, Math.min(t[1] + k, y12)]]);
+      var k2 = pi * scale(), t2 = m2(rotation_default(m2.rotate()).invert([0, 0]));
+      return clipExtent(x05 == null ? [[t2[0] - k2, t2[1] - k2], [t2[0] + k2, t2[1] + k2]] : project === mercatorRaw ? [[Math.max(t2[0] - k2, x05), y05], [Math.min(t2[0] + k2, x12), y12]] : [[x05, Math.max(t2[1] - k2, y05)], [x12, Math.min(t2[1] + k2, y12)]]);
     }
     return reclip();
   }
 
   // node_modules/d3-geo/src/projection/identity.js
   function identity_default2() {
-    var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, alpha = 0, ca, sa, x05 = null, y05, x12, y12, kx = 1, ky = 1, transform2 = transformer({
-      point: function(x, y) {
-        var p = projection2([x, y]);
-        this.stream.point(p[0], p[1]);
+    var k2 = 1, tx = 0, ty = 0, sx = 1, sy = 1, alpha = 0, ca, sa, x05 = null, y05, x12, y12, kx = 1, ky = 1, transform2 = transformer({
+      point: function(x2, y2) {
+        var p2 = projection2([x2, y2]);
+        this.stream.point(p2[0], p2[1]);
       }
     }), postclip = identity_default, cache, cacheStream;
     function reset() {
-      kx = k * sx;
-      ky = k * sy;
+      kx = k2 * sx;
+      ky = k2 * sy;
       cache = cacheStream = null;
       return projection2;
     }
-    function projection2(p) {
-      var x = p[0] * kx, y = p[1] * ky;
+    function projection2(p2) {
+      var x2 = p2[0] * kx, y2 = p2[1] * ky;
       if (alpha) {
-        var t = y * ca - x * sa;
-        x = x * ca + y * sa;
-        y = t;
+        var t2 = y2 * ca - x2 * sa;
+        x2 = x2 * ca + y2 * sa;
+        y2 = t2;
       }
-      return [x + tx, y + ty];
+      return [x2 + tx, y2 + ty];
     }
-    projection2.invert = function(p) {
-      var x = p[0] - tx, y = p[1] - ty;
+    projection2.invert = function(p2) {
+      var x2 = p2[0] - tx, y2 = p2[1] - ty;
       if (alpha) {
-        var t = y * ca + x * sa;
-        x = x * ca - y * sa;
-        y = t;
+        var t2 = y2 * ca + x2 * sa;
+        x2 = x2 * ca - y2 * sa;
+        y2 = t2;
       }
-      return [x / kx, y / ky];
+      return [x2 / kx, y2 / ky];
     };
     projection2.stream = function(stream) {
       return cache && cacheStream === stream ? cache : cache = transform2(postclip(cacheStream = stream));
     };
-    projection2.postclip = function(_) {
-      return arguments.length ? (postclip = _, x05 = y05 = x12 = y12 = null, reset()) : postclip;
+    projection2.postclip = function(_2) {
+      return arguments.length ? (postclip = _2, x05 = y05 = x12 = y12 = null, reset()) : postclip;
     };
-    projection2.clipExtent = function(_) {
-      return arguments.length ? (postclip = _ == null ? (x05 = y05 = x12 = y12 = null, identity_default) : clipRectangle(x05 = +_[0][0], y05 = +_[0][1], x12 = +_[1][0], y12 = +_[1][1]), reset()) : x05 == null ? null : [[x05, y05], [x12, y12]];
+    projection2.clipExtent = function(_2) {
+      return arguments.length ? (postclip = _2 == null ? (x05 = y05 = x12 = y12 = null, identity_default) : clipRectangle(x05 = +_2[0][0], y05 = +_2[0][1], x12 = +_2[1][0], y12 = +_2[1][1]), reset()) : x05 == null ? null : [[x05, y05], [x12, y12]];
     };
-    projection2.scale = function(_) {
-      return arguments.length ? (k = +_, reset()) : k;
+    projection2.scale = function(_2) {
+      return arguments.length ? (k2 = +_2, reset()) : k2;
     };
-    projection2.translate = function(_) {
-      return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
+    projection2.translate = function(_2) {
+      return arguments.length ? (tx = +_2[0], ty = +_2[1], reset()) : [tx, ty];
     };
-    projection2.angle = function(_) {
-      return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees;
+    projection2.angle = function(_2) {
+      return arguments.length ? (alpha = _2 % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees;
     };
-    projection2.reflectX = function(_) {
-      return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
+    projection2.reflectX = function(_2) {
+      return arguments.length ? (sx = _2 ? -1 : 1, reset()) : sx < 0;
     };
-    projection2.reflectY = function(_) {
-      return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
+    projection2.reflectY = function(_2) {
+      return arguments.length ? (sy = _2 ? -1 : 1, reset()) : sy < 0;
     };
     projection2.fitExtent = function(extent, object) {
       return fitExtent(projection2, extent, object);
 
   // modules/geo/geo.js
   var TAU = 2 * Math.PI;
-  var EQUATORIAL_RADIUS = 6356752314245179e-9;
-  var POLAR_RADIUS = 6378137;
+  var EQUATORIAL_RADIUS = 6378137;
+  var POLAR_RADIUS = 63567523e-1;
   function geoLatToMeters(dLat) {
     return dLat * (TAU * POLAR_RADIUS / 360);
   }
   function geoLonToMeters(dLon, atLat) {
     return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
   }
-  function geoMetersToLat(m) {
-    return m / (TAU * POLAR_RADIUS / 360);
+  function geoMetersToLat(m2) {
+    return m2 / (TAU * POLAR_RADIUS / 360);
   }
-  function geoMetersToLon(m, atLat) {
-    return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
+  function geoMetersToLon(m2, atLat) {
+    return Math.abs(atLat) >= 90 ? 0 : m2 / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
   }
   function geoMetersToOffset(meters, tileSize) {
     tileSize = tileSize || 256;
       -offset[1] * TAU * POLAR_RADIUS / tileSize
     ];
   }
-  function geoSphericalDistance(a, b) {
-    var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
-    var y = geoLatToMeters(a[1] - b[1]);
-    return Math.sqrt(x * x + y * y);
+  function geoSphericalDistance(a2, b2) {
+    var x2 = geoLonToMeters(a2[0] - b2[0], (a2[1] + b2[1]) / 2);
+    var y2 = geoLatToMeters(a2[1] - b2[1]);
+    return Math.sqrt(x2 * x2 + y2 * y2);
   }
-  function geoScaleToZoom(k, tileSize) {
+  function geoScaleToZoom(k2, tileSize) {
     tileSize = tileSize || 256;
     var log2ts = Math.log(tileSize) * Math.LOG2E;
-    return Math.log(k * TAU) / Math.LN2 - log2ts;
+    return Math.log(k2 * TAU) / Math.LN2 - log2ts;
   }
-  function geoZoomToScale(z, tileSize) {
+  function geoZoomToScale(z2, tileSize) {
     tileSize = tileSize || 256;
-    return tileSize * Math.pow(2, z) / TAU;
+    return tileSize * Math.pow(2, z2) / TAU;
   }
   function geoSphericalClosestNode(nodes, point) {
     var minDistance = Infinity, distance;
     var indexOfMin;
-    for (var i2 in nodes) {
-      distance = geoSphericalDistance(nodes[i2].loc, point);
+    for (var i3 in nodes) {
+      distance = geoSphericalDistance(nodes[i3].loc, point);
       if (distance < minDistance) {
         minDistance = distance;
-        indexOfMin = i2;
+        indexOfMin = i3;
       }
     }
     if (indexOfMin !== void 0) {
       return this[0][0] === obj[0][0] && this[0][1] === obj[0][1] && this[1][0] === obj[1][0] && this[1][1] === obj[1][1];
     },
     extend: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       return geoExtent(
         [Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])],
         [Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])]
       ];
     },
     contains: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       return obj[0][0] >= this[0][0] && obj[0][1] >= this[0][1] && obj[1][0] <= this[1][0] && obj[1][1] <= this[1][1];
     },
     intersects: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       return obj[0][0] <= this[1][0] && obj[0][1] <= this[1][1] && obj[1][0] >= this[0][0] && obj[1][1] >= this[0][1];
     },
     intersection: function(obj) {
-      if (!this.intersects(obj))
-        return new geoExtent();
+      if (!this.intersects(obj)) return new geoExtent();
       return new geoExtent(
         [Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])],
         [Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])]
       );
     },
     percentContainedIn: function(obj) {
-      if (!(obj instanceof geoExtent))
-        obj = new geoExtent(obj);
+      if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
       var a1 = this.intersection(obj).area();
       var a2 = this.area();
       if (a1 === Infinity || a2 === Infinity) {
     },
     toParam: function() {
       return this.rectangle().join(",");
+    },
+    split: function() {
+      const center = this.center();
+      return [
+        geoExtent(this[0], center),
+        geoExtent([center[0], this[0][1]], [this[1][0], center[1]]),
+        geoExtent(center, this[1]),
+        geoExtent([this[0][0], center[1]], [center[0], this[1][1]])
+      ];
     }
   });
 
   // node_modules/d3-polygon/src/area.js
   function area_default3(polygon2) {
-    var i2 = -1, n2 = polygon2.length, a, b = polygon2[n2 - 1], area = 0;
-    while (++i2 < n2) {
-      a = b;
-      b = polygon2[i2];
-      area += a[1] * b[0] - a[0] * b[1];
+    var i3 = -1, n3 = polygon2.length, a2, b2 = polygon2[n3 - 1], area = 0;
+    while (++i3 < n3) {
+      a2 = b2;
+      b2 = polygon2[i3];
+      area += a2[1] * b2[0] - a2[0] * b2[1];
     }
     return area / 2;
   }
 
   // node_modules/d3-polygon/src/centroid.js
   function centroid_default2(polygon2) {
-    var i2 = -1, n2 = polygon2.length, x = 0, y = 0, a, b = polygon2[n2 - 1], c, k = 0;
-    while (++i2 < n2) {
-      a = b;
-      b = polygon2[i2];
-      k += c = a[0] * b[1] - b[0] * a[1];
-      x += (a[0] + b[0]) * c;
-      y += (a[1] + b[1]) * c;
+    var i3 = -1, n3 = polygon2.length, x2 = 0, y2 = 0, a2, b2 = polygon2[n3 - 1], c2, k2 = 0;
+    while (++i3 < n3) {
+      a2 = b2;
+      b2 = polygon2[i3];
+      k2 += c2 = a2[0] * b2[1] - b2[0] * a2[1];
+      x2 += (a2[0] + b2[0]) * c2;
+      y2 += (a2[1] + b2[1]) * c2;
     }
-    return k *= 3, [x / k, y / k];
+    return k2 *= 3, [x2 / k2, y2 / k2];
   }
 
   // node_modules/d3-polygon/src/cross.js
-  function cross_default(a, b, c) {
-    return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
+  function cross_default(a2, b2, c2) {
+    return (b2[0] - a2[0]) * (c2[1] - a2[1]) - (b2[1] - a2[1]) * (c2[0] - a2[0]);
   }
 
   // node_modules/d3-polygon/src/hull.js
-  function lexicographicOrder(a, b) {
-    return a[0] - b[0] || a[1] - b[1];
+  function lexicographicOrder(a2, b2) {
+    return a2[0] - b2[0] || a2[1] - b2[1];
   }
   function computeUpperHullIndexes(points) {
-    const n2 = points.length, indexes = [0, 1];
-    let size = 2, i2;
-    for (i2 = 2; i2 < n2; ++i2) {
-      while (size > 1 && cross_default(points[indexes[size - 2]], points[indexes[size - 1]], points[i2]) <= 0)
-        --size;
-      indexes[size++] = i2;
+    const n3 = points.length, indexes = [0, 1];
+    let size = 2, i3;
+    for (i3 = 2; i3 < n3; ++i3) {
+      while (size > 1 && cross_default(points[indexes[size - 2]], points[indexes[size - 1]], points[i3]) <= 0) --size;
+      indexes[size++] = i3;
     }
     return indexes.slice(0, size);
   }
   function hull_default(points) {
-    if ((n2 = points.length) < 3)
-      return null;
-    var i2, n2, sortedPoints = new Array(n2), flippedPoints = new Array(n2);
-    for (i2 = 0; i2 < n2; ++i2)
-      sortedPoints[i2] = [+points[i2][0], +points[i2][1], i2];
+    if ((n3 = points.length) < 3) return null;
+    var i3, n3, sortedPoints = new Array(n3), flippedPoints = new Array(n3);
+    for (i3 = 0; i3 < n3; ++i3) sortedPoints[i3] = [+points[i3][0], +points[i3][1], i3];
     sortedPoints.sort(lexicographicOrder);
-    for (i2 = 0; i2 < n2; ++i2)
-      flippedPoints[i2] = [sortedPoints[i2][0], -sortedPoints[i2][1]];
+    for (i3 = 0; i3 < n3; ++i3) flippedPoints[i3] = [sortedPoints[i3][0], -sortedPoints[i3][1]];
     var upperIndexes = computeUpperHullIndexes(sortedPoints), lowerIndexes = computeUpperHullIndexes(flippedPoints);
     var skipLeft = lowerIndexes[0] === upperIndexes[0], skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1], hull = [];
-    for (i2 = upperIndexes.length - 1; i2 >= 0; --i2)
-      hull.push(points[sortedPoints[upperIndexes[i2]][2]]);
-    for (i2 = +skipLeft; i2 < lowerIndexes.length - skipRight; ++i2)
-      hull.push(points[sortedPoints[lowerIndexes[i2]][2]]);
+    for (i3 = upperIndexes.length - 1; i3 >= 0; --i3) hull.push(points[sortedPoints[upperIndexes[i3]][2]]);
+    for (i3 = +skipLeft; i3 < lowerIndexes.length - skipRight; ++i3) hull.push(points[sortedPoints[lowerIndexes[i3]][2]]);
     return hull;
   }
 
   // modules/geo/vector.js
-  function geoVecEqual(a, b, epsilon3) {
+  function geoVecEqual(a2, b2, epsilon3) {
     if (epsilon3) {
-      return Math.abs(a[0] - b[0]) <= epsilon3 && Math.abs(a[1] - b[1]) <= epsilon3;
+      return Math.abs(a2[0] - b2[0]) <= epsilon3 && Math.abs(a2[1] - b2[1]) <= epsilon3;
     } else {
-      return a[0] === b[0] && a[1] === b[1];
+      return a2[0] === b2[0] && a2[1] === b2[1];
     }
   }
-  function geoVecAdd(a, b) {
-    return [a[0] + b[0], a[1] + b[1]];
+  function geoVecAdd(a2, b2) {
+    return [a2[0] + b2[0], a2[1] + b2[1]];
   }
-  function geoVecSubtract(a, b) {
-    return [a[0] - b[0], a[1] - b[1]];
+  function geoVecSubtract(a2, b2) {
+    return [a2[0] - b2[0], a2[1] - b2[1]];
   }
-  function geoVecScale(a, mag) {
-    return [a[0] * mag, a[1] * mag];
+  function geoVecScale(a2, mag) {
+    return [a2[0] * mag, a2[1] * mag];
   }
-  function geoVecFloor(a) {
-    return [Math.floor(a[0]), Math.floor(a[1])];
+  function geoVecFloor(a2) {
+    return [Math.floor(a2[0]), Math.floor(a2[1])];
   }
-  function geoVecInterp(a, b, t) {
+  function geoVecInterp(a2, b2, t2) {
     return [
-      a[0] + (b[0] - a[0]) * t,
-      a[1] + (b[1] - a[1]) * t
+      a2[0] + (b2[0] - a2[0]) * t2,
+      a2[1] + (b2[1] - a2[1]) * t2
     ];
   }
-  function geoVecLength(a, b) {
-    return Math.sqrt(geoVecLengthSquare(a, b));
+  function geoVecLength(a2, b2) {
+    return Math.sqrt(geoVecLengthSquare(a2, b2));
   }
-  function geoVecLengthSquare(a, b) {
-    b = b || [0, 0];
-    var x = a[0] - b[0];
-    var y = a[1] - b[1];
-    return x * x + y * y;
+  function geoVecLengthSquare(a2, b2) {
+    b2 = b2 || [0, 0];
+    var x2 = a2[0] - b2[0];
+    var y2 = a2[1] - b2[1];
+    return x2 * x2 + y2 * y2;
   }
-  function geoVecNormalize(a) {
-    var length = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
-    if (length !== 0) {
-      return geoVecScale(a, 1 / length);
+  function geoVecNormalize(a2) {
+    var length2 = Math.sqrt(a2[0] * a2[0] + a2[1] * a2[1]);
+    if (length2 !== 0) {
+      return geoVecScale(a2, 1 / length2);
     }
     return [0, 0];
   }
-  function geoVecAngle(a, b) {
-    return Math.atan2(b[1] - a[1], b[0] - a[0]);
+  function geoVecAngle(a2, b2) {
+    return Math.atan2(b2[1] - a2[1], b2[0] - a2[0]);
   }
-  function geoVecDot(a, b, origin) {
+  function geoVecDot(a2, b2, origin) {
     origin = origin || [0, 0];
-    var p = geoVecSubtract(a, origin);
-    var q = geoVecSubtract(b, origin);
-    return p[0] * q[0] + p[1] * q[1];
+    var p2 = geoVecSubtract(a2, origin);
+    var q2 = geoVecSubtract(b2, origin);
+    return p2[0] * q2[0] + p2[1] * q2[1];
   }
-  function geoVecNormalizedDot(a, b, origin) {
+  function geoVecNormalizedDot(a2, b2, origin) {
     origin = origin || [0, 0];
-    var p = geoVecNormalize(geoVecSubtract(a, origin));
-    var q = geoVecNormalize(geoVecSubtract(b, origin));
-    return geoVecDot(p, q);
+    var p2 = geoVecNormalize(geoVecSubtract(a2, origin));
+    var q2 = geoVecNormalize(geoVecSubtract(b2, origin));
+    return geoVecDot(p2, q2);
   }
-  function geoVecCross(a, b, origin) {
+  function geoVecCross(a2, b2, origin) {
     origin = origin || [0, 0];
-    var p = geoVecSubtract(a, origin);
-    var q = geoVecSubtract(b, origin);
-    return p[0] * q[1] - p[1] * q[0];
+    var p2 = geoVecSubtract(a2, origin);
+    var q2 = geoVecSubtract(b2, origin);
+    return p2[0] * q2[1] - p2[1] * q2[0];
   }
-  function geoVecProject(a, points) {
+  function geoVecProject(a2, points) {
     var min3 = Infinity;
     var idx;
     var target;
-    for (var i2 = 0; i2 < points.length - 1; i2++) {
-      var o = points[i2];
-      var s = geoVecSubtract(points[i2 + 1], o);
-      var v = geoVecSubtract(a, o);
-      var proj = geoVecDot(v, s) / geoVecDot(s, s);
-      var p;
+    for (var i3 = 0; i3 < points.length - 1; i3++) {
+      var o2 = points[i3];
+      var s2 = geoVecSubtract(points[i3 + 1], o2);
+      var v2 = geoVecSubtract(a2, o2);
+      var proj = geoVecDot(v2, s2) / geoVecDot(s2, s2);
+      var p2;
       if (proj < 0) {
-        p = o;
+        p2 = o2;
       } else if (proj > 1) {
-        p = points[i2 + 1];
+        p2 = points[i3 + 1];
       } else {
-        p = [o[0] + proj * s[0], o[1] + proj * s[1]];
+        p2 = [o2[0] + proj * s2[0], o2[1] + proj * s2[1]];
       }
-      var dist = geoVecLength(p, a);
+      var dist = geoVecLength(p2, a2);
       if (dist < min3) {
         min3 = dist;
-        idx = i2 + 1;
-        target = p;
+        idx = i3 + 1;
+        target = p2;
       }
     }
     if (idx !== void 0) {
   }
 
   // modules/geo/geom.js
-  function geoAngle(a, b, projection2) {
-    return geoVecAngle(projection2(a.loc), projection2(b.loc));
+  function geoAngle(a2, b2, projection2) {
+    return geoVecAngle(projection2(a2.loc), projection2(b2.loc));
   }
-  function geoEdgeEqual(a, b) {
-    return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
+  function geoEdgeEqual(a2, b2) {
+    return a2[0] === b2[0] && a2[1] === b2[1] || a2[0] === b2[1] && a2[1] === b2[0];
   }
   function geoRotate(points, angle2, around) {
     return points.map(function(point) {
   }
   function geoChooseEdge(nodes, point, projection2, activeID) {
     var dist = geoVecLength;
-    var points = nodes.map(function(n2) {
-      return projection2(n2.loc);
+    var points = nodes.map(function(n3) {
+      return projection2(n3.loc);
     });
-    var ids = nodes.map(function(n2) {
-      return n2.id;
+    var ids = nodes.map(function(n3) {
+      return n3.id;
     });
     var min3 = Infinity;
     var idx;
     var loc;
-    for (var i2 = 0; i2 < points.length - 1; i2++) {
-      if (ids[i2] === activeID || ids[i2 + 1] === activeID)
-        continue;
-      var o = points[i2];
-      var s = geoVecSubtract(points[i2 + 1], o);
-      var v = geoVecSubtract(point, o);
-      var proj = geoVecDot(v, s) / geoVecDot(s, s);
-      var p;
+    for (var i3 = 0; i3 < points.length - 1; i3++) {
+      if (ids[i3] === activeID || ids[i3 + 1] === activeID) continue;
+      var o2 = points[i3];
+      var s2 = geoVecSubtract(points[i3 + 1], o2);
+      var v2 = geoVecSubtract(point, o2);
+      var proj = geoVecDot(v2, s2) / geoVecDot(s2, s2);
+      var p2;
       if (proj < 0) {
-        p = o;
+        p2 = o2;
       } else if (proj > 1) {
-        p = points[i2 + 1];
+        p2 = points[i3 + 1];
       } else {
-        p = [o[0] + proj * s[0], o[1] + proj * s[1]];
+        p2 = [o2[0] + proj * s2[0], o2[1] + proj * s2[1]];
       }
-      var d = dist(p, point);
-      if (d < min3) {
-        min3 = d;
-        idx = i2 + 1;
-        loc = projection2.invert(p);
+      var d2 = dist(p2, point);
+      if (d2 < min3) {
+        min3 = d2;
+        idx = i3 + 1;
+        loc = projection2.invert(p2);
       }
     }
     if (idx !== void 0) {
   function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
     var actives = [];
     var inactives = [];
-    var j2, k, n1, n2, segment;
+    var j2, k2, n1, n22, segment;
     for (j2 = 0; j2 < activeNodes.length - 1; j2++) {
       n1 = activeNodes[j2];
-      n2 = activeNodes[j2 + 1];
-      segment = [n1.loc, n2.loc];
-      if (n1.id === activeID || n2.id === activeID) {
+      n22 = activeNodes[j2 + 1];
+      segment = [n1.loc, n22.loc];
+      if (n1.id === activeID || n22.id === activeID) {
         actives.push(segment);
       }
     }
     for (j2 = 0; j2 < inactiveNodes.length - 1; j2++) {
       n1 = inactiveNodes[j2];
-      n2 = inactiveNodes[j2 + 1];
-      segment = [n1.loc, n2.loc];
+      n22 = inactiveNodes[j2 + 1];
+      segment = [n1.loc, n22.loc];
       inactives.push(segment);
     }
     for (j2 = 0; j2 < actives.length; j2++) {
-      for (k = 0; k < inactives.length; k++) {
-        var p = actives[j2];
-        var q = inactives[k];
-        var hit = geoLineIntersection(p, q);
+      for (k2 = 0; k2 < inactives.length; k2++) {
+        var p2 = actives[j2];
+        var q2 = inactives[k2];
+        var hit = geoLineIntersection(p2, q2);
         if (hit) {
           return true;
         }
   function geoHasSelfIntersections(nodes, activeID) {
     var actives = [];
     var inactives = [];
-    var j2, k;
+    var j2, k2;
     for (j2 = 0; j2 < nodes.length - 1; j2++) {
       var n1 = nodes[j2];
-      var n2 = nodes[j2 + 1];
-      var segment = [n1.loc, n2.loc];
-      if (n1.id === activeID || n2.id === activeID) {
+      var n22 = nodes[j2 + 1];
+      var segment = [n1.loc, n22.loc];
+      if (n1.id === activeID || n22.id === activeID) {
         actives.push(segment);
       } else {
         inactives.push(segment);
       }
     }
     for (j2 = 0; j2 < actives.length; j2++) {
-      for (k = 0; k < inactives.length; k++) {
-        var p = actives[j2];
-        var q = inactives[k];
-        if (geoVecEqual(p[1], q[0]) || geoVecEqual(p[0], q[1]) || geoVecEqual(p[0], q[0]) || geoVecEqual(p[1], q[1])) {
+      for (k2 = 0; k2 < inactives.length; k2++) {
+        var p2 = actives[j2];
+        var q2 = inactives[k2];
+        if (geoVecEqual(p2[1], q2[0]) || geoVecEqual(p2[0], q2[1]) || geoVecEqual(p2[0], q2[0]) || geoVecEqual(p2[1], q2[1])) {
           continue;
         }
-        var hit = geoLineIntersection(p, q);
+        var hit = geoLineIntersection(p2, q2);
         if (hit) {
           var epsilon3 = 1e-8;
-          if (geoVecEqual(p[1], hit, epsilon3) || geoVecEqual(p[0], hit, epsilon3) || geoVecEqual(q[1], hit, epsilon3) || geoVecEqual(q[0], hit, epsilon3)) {
+          if (geoVecEqual(p2[1], hit, epsilon3) || geoVecEqual(p2[0], hit, epsilon3) || geoVecEqual(q2[1], hit, epsilon3) || geoVecEqual(q2[0], hit, epsilon3)) {
             continue;
           } else {
             return true;
     }
     return false;
   }
-  function geoLineIntersection(a, b) {
-    var p = [a[0][0], a[0][1]];
-    var p2 = [a[1][0], a[1][1]];
-    var q = [b[0][0], b[0][1]];
-    var q2 = [b[1][0], b[1][1]];
-    var r = geoVecSubtract(p2, p);
-    var s = geoVecSubtract(q2, q);
-    var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
-    var denominator = geoVecCross(r, s);
+  function geoLineIntersection(a2, b2) {
+    var p2 = [a2[0][0], a2[0][1]];
+    var p22 = [a2[1][0], a2[1][1]];
+    var q2 = [b2[0][0], b2[0][1]];
+    var q22 = [b2[1][0], b2[1][1]];
+    var r2 = geoVecSubtract(p22, p2);
+    var s2 = geoVecSubtract(q22, q2);
+    var uNumerator = geoVecCross(geoVecSubtract(q2, p2), r2);
+    var denominator = geoVecCross(r2, s2);
     if (uNumerator && denominator) {
-      var u = uNumerator / denominator;
-      var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
-      if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
-        return geoVecInterp(p, p2, t);
+      var u2 = uNumerator / denominator;
+      var t2 = geoVecCross(geoVecSubtract(q2, p2), s2) / denominator;
+      if (t2 >= 0 && t2 <= 1 && u2 >= 0 && u2 <= 1) {
+        return geoVecInterp(p2, p22, t2);
       }
     }
     return null;
   }
   function geoPathIntersections(path1, path2) {
     var intersections = [];
-    for (var i2 = 0; i2 < path1.length - 1; i2++) {
+    for (var i3 = 0; i3 < path1.length - 1; i3++) {
       for (var j2 = 0; j2 < path2.length - 1; j2++) {
-        var a = [path1[i2], path1[i2 + 1]];
-        var b = [path2[j2], path2[j2 + 1]];
-        var hit = geoLineIntersection(a, b);
+        var a2 = [path1[i3], path1[i3 + 1]];
+        var b2 = [path2[j2], path2[j2 + 1]];
+        var hit = geoLineIntersection(a2, b2);
         if (hit) {
           intersections.push(hit);
         }
     return intersections;
   }
   function geoPathHasIntersections(path1, path2) {
-    for (var i2 = 0; i2 < path1.length - 1; i2++) {
+    for (var i3 = 0; i3 < path1.length - 1; i3++) {
       for (var j2 = 0; j2 < path2.length - 1; j2++) {
-        var a = [path1[i2], path1[i2 + 1]];
-        var b = [path2[j2], path2[j2 + 1]];
-        var hit = geoLineIntersection(a, b);
+        var a2 = [path1[i3], path1[i3 + 1]];
+        var b2 = [path2[j2], path2[j2 + 1]];
+        var hit = geoLineIntersection(a2, b2);
         if (hit) {
           return true;
         }
     return false;
   }
   function geoPointInPolygon(point, polygon2) {
-    var x = point[0];
-    var y = point[1];
+    var x2 = point[0];
+    var y2 = point[1];
     var inside = false;
-    for (var i2 = 0, j2 = polygon2.length - 1; i2 < polygon2.length; j2 = i2++) {
-      var xi = polygon2[i2][0];
-      var yi = polygon2[i2][1];
+    for (var i3 = 0, j2 = polygon2.length - 1; i3 < polygon2.length; j2 = i3++) {
+      var xi = polygon2[i3][0];
+      var yi = polygon2[i3][1];
       var xj = polygon2[j2][0];
       var yj = polygon2[j2][1];
-      var intersect2 = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
-      if (intersect2)
-        inside = !inside;
+      var intersect2 = yi > y2 !== yj > y2 && x2 < (xj - xi) * (y2 - yi) / (yj - yi) + xi;
+      if (intersect2) inside = !inside;
     }
     return inside;
   }
     var ssrExtent = [];
     var ssrAngle = 0;
     var c1 = hull[0];
-    for (var i2 = 0; i2 <= hull.length - 1; i2++) {
-      var c2 = i2 === hull.length - 1 ? hull[0] : hull[i2 + 1];
+    for (var i3 = 0; i3 <= hull.length - 1; i3++) {
+      var c2 = i3 === hull.length - 1 ? hull[0] : hull[i3 + 1];
       var angle2 = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
       var poly = geoRotate(hull, -angle2, centroid);
       var extent = poly.reduce(function(extent2, point) {
     };
   }
   function geoPathLength(path) {
-    var length = 0;
-    for (var i2 = 0; i2 < path.length - 1; i2++) {
-      length += geoVecLength(path[i2], path[i2 + 1]);
+    var length2 = 0;
+    for (var i3 = 0; i3 < path.length - 1; i3++) {
+      length2 += geoVecLength(path[i3], path[i3 + 1]);
     }
-    return length;
+    return length2;
   }
   function geoViewportEdge(point, dimensions) {
     var pad2 = [80, 20, 50, 20];
-    var x = 0;
-    var y = 0;
+    var x2 = 0;
+    var y2 = 0;
     if (point[0] > dimensions[0] - pad2[1]) {
-      x = -10;
+      x2 = -10;
     }
     if (point[0] < pad2[3]) {
-      x = 10;
+      x2 = 10;
     }
     if (point[1] > dimensions[1] - pad2[2]) {
-      y = -10;
+      y2 = -10;
     }
     if (point[1] < pad2[0]) {
-      y = 10;
+      y2 = 10;
     }
-    if (x || y) {
-      return [x, y];
+    if (x2 || y2) {
+      return [x2, y2];
     } else {
       return null;
     }
   var noop2 = { value: () => {
   } };
   function dispatch() {
-    for (var i2 = 0, n2 = arguments.length, _ = {}, t; i2 < n2; ++i2) {
-      if (!(t = arguments[i2] + "") || t in _ || /[\s.]/.test(t))
-        throw new Error("illegal type: " + t);
-      _[t] = [];
+    for (var i3 = 0, n3 = arguments.length, _2 = {}, t2; i3 < n3; ++i3) {
+      if (!(t2 = arguments[i3] + "") || t2 in _2 || /[\s.]/.test(t2)) throw new Error("illegal type: " + t2);
+      _2[t2] = [];
     }
-    return new Dispatch(_);
+    return new Dispatch(_2);
   }
-  function Dispatch(_) {
-    this._ = _;
+  function Dispatch(_2) {
+    this._ = _2;
   }
   function parseTypenames(typenames, types) {
-    return typenames.trim().split(/^|\s+/).map(function(t) {
-      var name = "", i2 = t.indexOf(".");
-      if (i2 >= 0)
-        name = t.slice(i2 + 1), t = t.slice(0, i2);
-      if (t && !types.hasOwnProperty(t))
-        throw new Error("unknown type: " + t);
-      return { type: t, name };
+    return typenames.trim().split(/^|\s+/).map(function(t2) {
+      var name = "", i3 = t2.indexOf(".");
+      if (i3 >= 0) name = t2.slice(i3 + 1), t2 = t2.slice(0, i3);
+      if (t2 && !types.hasOwnProperty(t2)) throw new Error("unknown type: " + t2);
+      return { type: t2, name };
     });
   }
   Dispatch.prototype = dispatch.prototype = {
     constructor: Dispatch,
     on: function(typename, callback) {
-      var _ = this._, T = parseTypenames(typename + "", _), t, i2 = -1, n2 = T.length;
+      var _2 = this._, T2 = parseTypenames(typename + "", _2), t2, i3 = -1, n3 = T2.length;
       if (arguments.length < 2) {
-        while (++i2 < n2)
-          if ((t = (typename = T[i2]).type) && (t = get(_[t], typename.name)))
-            return t;
+        while (++i3 < n3) if ((t2 = (typename = T2[i3]).type) && (t2 = get(_2[t2], typename.name))) return t2;
         return;
       }
-      if (callback != null && typeof callback !== "function")
-        throw new Error("invalid callback: " + callback);
-      while (++i2 < n2) {
-        if (t = (typename = T[i2]).type)
-          _[t] = set(_[t], typename.name, callback);
-        else if (callback == null)
-          for (t in _)
-            _[t] = set(_[t], typename.name, null);
+      if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
+      while (++i3 < n3) {
+        if (t2 = (typename = T2[i3]).type) _2[t2] = set(_2[t2], typename.name, callback);
+        else if (callback == null) for (t2 in _2) _2[t2] = set(_2[t2], typename.name, null);
       }
       return this;
     },
     copy: function() {
-      var copy2 = {}, _ = this._;
-      for (var t in _)
-        copy2[t] = _[t].slice();
+      var copy2 = {}, _2 = this._;
+      for (var t2 in _2) copy2[t2] = _2[t2].slice();
       return new Dispatch(copy2);
     },
-    call: function(type3, 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)
-        t[i2].value.apply(that, args);
+    call: function(type2, that) {
+      if ((n3 = arguments.length - 2) > 0) for (var args = new Array(n3), i3 = 0, n3, t2; i3 < n3; ++i3) args[i3] = arguments[i3 + 2];
+      if (!this._.hasOwnProperty(type2)) throw new Error("unknown type: " + type2);
+      for (t2 = this._[type2], i3 = 0, n3 = t2.length; i3 < n3; ++i3) t2[i3].value.apply(that, args);
     },
-    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)
-        t[i2].value.apply(that, args);
+    apply: function(type2, that, args) {
+      if (!this._.hasOwnProperty(type2)) throw new Error("unknown type: " + type2);
+      for (var t2 = this._[type2], i3 = 0, n3 = t2.length; i3 < n3; ++i3) t2[i3].value.apply(that, args);
     }
   };
-  function get(type3, name) {
-    for (var i2 = 0, n2 = type3.length, c; i2 < n2; ++i2) {
-      if ((c = type3[i2]).name === name) {
-        return c.value;
+  function get(type2, name) {
+    for (var i3 = 0, n3 = type2.length, c2; i3 < n3; ++i3) {
+      if ((c2 = type2[i3]).name === name) {
+        return c2.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 i3 = 0, n3 = type2.length; i3 < n3; ++i3) {
+      if (type2[i3].name === name) {
+        type2[i3] = noop2, type2 = type2.slice(0, i3).concat(type2.slice(i3 + 1));
         break;
       }
     }
-    if (callback != null)
-      type3.push({ name, value: callback });
-    return type3;
+    if (callback != null) type2.push({ name, value: callback });
+    return type2;
   }
   var dispatch_default = dispatch;
 
 
   // node_modules/d3-selection/src/namespace.js
   function namespace_default(name) {
-    var prefix = name += "", i2 = prefix.indexOf(":");
-    if (i2 >= 0 && (prefix = name.slice(0, i2)) !== "xmlns")
-      name = name.slice(i2 + 1);
+    var prefix = name += "", i3 = prefix.indexOf(":");
+    if (i3 >= 0 && (prefix = name.slice(0, i3)) !== "xmlns") name = name.slice(i3 + 1);
     return namespaces_default.hasOwnProperty(prefix) ? { space: namespaces_default[prefix], local: name } : name;
   }
 
 
   // node_modules/d3-selection/src/selection/select.js
   function select_default(select) {
-    if (typeof select !== "function")
-      select = selector_default(select);
-    for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, subgroup = subgroups[j2] = new Array(n2), node, subnode, i2 = 0; i2 < n2; ++i2) {
-        if ((node = group[i2]) && (subnode = select.call(node, node.__data__, i2, group))) {
-          if ("__data__" in node)
-            subnode.__data__ = node.__data__;
-          subgroup[i2] = subnode;
+    if (typeof select !== "function") select = selector_default(select);
+    for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = new Array(n3), node, subnode, i3 = 0; i3 < n3; ++i3) {
+        if ((node = group[i3]) && (subnode = select.call(node, node.__data__, i3, group))) {
+          if ("__data__" in node) subnode.__data__ = node.__data__;
+          subgroup[i3] = subnode;
         }
       }
     }
   }
 
   // node_modules/d3-selection/src/array.js
-  function array(x) {
-    return x == null ? [] : Array.isArray(x) ? x : Array.from(x);
+  function array(x2) {
+    return x2 == null ? [] : Array.isArray(x2) ? x2 : Array.from(x2);
   }
 
   // node_modules/d3-selection/src/selectorAll.js
     };
   }
   function selectAll_default(select) {
-    if (typeof select === "function")
-      select = arrayAll(select);
-    else
-      select = selectorAll_default(select);
-    for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, node, i2 = 0; i2 < n2; ++i2) {
-        if (node = group[i2]) {
-          subgroups.push(select.call(node, node.__data__, i2, group));
+    if (typeof select === "function") select = arrayAll(select);
+    else select = selectorAll_default(select);
+    for (var groups = this._groups, m2 = groups.length, subgroups = [], parents = [], j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, node, i3 = 0; i3 < n3; ++i3) {
+        if (node = group[i3]) {
+          subgroups.push(select.call(node, node.__data__, i3, group));
           parents.push(node);
         }
       }
 
   // node_modules/d3-selection/src/selection/filter.js
   function filter_default(match) {
-    if (typeof match !== "function")
-      match = matcher_default(match);
-    for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, subgroup = subgroups[j2] = [], node, i2 = 0; i2 < n2; ++i2) {
-        if ((node = group[i2]) && match.call(node, node.__data__, i2, group)) {
+    if (typeof match !== "function") match = matcher_default(match);
+    for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = [], node, i3 = 0; i3 < n3; ++i3) {
+        if ((node = group[i3]) && match.call(node, node.__data__, i3, group)) {
           subgroup.push(node);
         }
       }
   };
 
   // node_modules/d3-selection/src/constant.js
-  function constant_default(x) {
+  function constant_default(x2) {
     return function() {
-      return x;
+      return x2;
     };
   }
 
   // node_modules/d3-selection/src/selection/data.js
   function bindIndex(parent, group, enter, update, exit, data) {
-    var i2 = 0, node, groupLength = group.length, dataLength = data.length;
-    for (; i2 < dataLength; ++i2) {
-      if (node = group[i2]) {
-        node.__data__ = data[i2];
-        update[i2] = node;
+    var i3 = 0, node, groupLength = group.length, dataLength = data.length;
+    for (; i3 < dataLength; ++i3) {
+      if (node = group[i3]) {
+        node.__data__ = data[i3];
+        update[i3] = node;
       } else {
-        enter[i2] = new EnterNode(parent, data[i2]);
+        enter[i3] = new EnterNode(parent, data[i3]);
       }
     }
-    for (; i2 < groupLength; ++i2) {
-      if (node = group[i2]) {
-        exit[i2] = node;
+    for (; i3 < groupLength; ++i3) {
+      if (node = group[i3]) {
+        exit[i3] = node;
       }
     }
   }
   function bindKey(parent, group, enter, update, exit, data, key) {
-    var i2, node, nodeByKeyValue = /* @__PURE__ */ new Map(), groupLength = group.length, dataLength = data.length, keyValues = new Array(groupLength), keyValue;
-    for (i2 = 0; i2 < groupLength; ++i2) {
-      if (node = group[i2]) {
-        keyValues[i2] = keyValue = key.call(node, node.__data__, i2, group) + "";
+    var i3, node, nodeByKeyValue = /* @__PURE__ */ new Map(), groupLength = group.length, dataLength = data.length, keyValues = new Array(groupLength), keyValue;
+    for (i3 = 0; i3 < groupLength; ++i3) {
+      if (node = group[i3]) {
+        keyValues[i3] = keyValue = key.call(node, node.__data__, i3, group) + "";
         if (nodeByKeyValue.has(keyValue)) {
-          exit[i2] = node;
+          exit[i3] = node;
         } else {
           nodeByKeyValue.set(keyValue, node);
         }
       }
     }
-    for (i2 = 0; i2 < dataLength; ++i2) {
-      keyValue = key.call(parent, data[i2], i2, data) + "";
+    for (i3 = 0; i3 < dataLength; ++i3) {
+      keyValue = key.call(parent, data[i3], i3, data) + "";
       if (node = nodeByKeyValue.get(keyValue)) {
-        update[i2] = node;
-        node.__data__ = data[i2];
+        update[i3] = node;
+        node.__data__ = data[i3];
         nodeByKeyValue.delete(keyValue);
       } else {
-        enter[i2] = new EnterNode(parent, data[i2]);
+        enter[i3] = new EnterNode(parent, data[i3]);
       }
     }
-    for (i2 = 0; i2 < groupLength; ++i2) {
-      if ((node = group[i2]) && nodeByKeyValue.get(keyValues[i2]) === node) {
-        exit[i2] = node;
+    for (i3 = 0; i3 < groupLength; ++i3) {
+      if ((node = group[i3]) && nodeByKeyValue.get(keyValues[i3]) === node) {
+        exit[i3] = node;
       }
     }
   }
     return node.__data__;
   }
   function data_default(value, key) {
-    if (!arguments.length)
-      return Array.from(this, datum);
+    if (!arguments.length) return Array.from(this, datum);
     var bind = key ? bindKey : bindIndex, parents = this._parents, groups = this._groups;
-    if (typeof value !== "function")
-      value = constant_default(value);
-    for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j2 = 0; j2 < m; ++j2) {
+    if (typeof value !== "function") value = constant_default(value);
+    for (var m2 = groups.length, update = new Array(m2), enter = new Array(m2), exit = new Array(m2), j2 = 0; j2 < m2; ++j2) {
       var parent = parents[j2], group = groups[j2], groupLength = group.length, data = arraylike(value.call(parent, parent && parent.__data__, j2, parents)), dataLength = data.length, enterGroup = enter[j2] = new Array(dataLength), updateGroup = update[j2] = new Array(dataLength), exitGroup = exit[j2] = new Array(groupLength);
       bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
       for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
         if (previous = enterGroup[i0]) {
-          if (i0 >= i1)
-            i1 = i0 + 1;
-          while (!(next = updateGroup[i1]) && ++i1 < dataLength)
-            ;
+          if (i0 >= i1) i1 = i0 + 1;
+          while (!(next = updateGroup[i1]) && ++i1 < dataLength) ;
           previous._next = next || null;
         }
       }
     var enter = this.enter(), update = this, exit = this.exit();
     if (typeof onenter === "function") {
       enter = onenter(enter);
-      if (enter)
-        enter = enter.selection();
+      if (enter) enter = enter.selection();
     } else {
       enter = enter.append(onenter + "");
     }
     if (onupdate != null) {
       update = onupdate(update);
-      if (update)
-        update = update.selection();
+      if (update) update = update.selection();
     }
-    if (onexit == null)
-      exit.remove();
-    else
-      onexit(exit);
+    if (onexit == null) exit.remove();
+    else onexit(exit);
     return enter && update ? enter.merge(update).order() : update;
   }
 
   // node_modules/d3-selection/src/selection/merge.js
   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) {
-        if (node = group0[i2] || group1[i2]) {
-          merge3[i2] = node;
+    for (var groups0 = this._groups, groups1 = selection2._groups, m0 = groups0.length, m1 = groups1.length, m2 = Math.min(m0, m1), merges = new Array(m0), j2 = 0; j2 < m2; ++j2) {
+      for (var group0 = groups0[j2], group1 = groups1[j2], n3 = group0.length, merge2 = merges[j2] = new Array(n3), node, i3 = 0; i3 < n3; ++i3) {
+        if (node = group0[i3] || group1[i3]) {
+          merge2[i3] = node;
         }
       }
     }
 
   // node_modules/d3-selection/src/selection/order.js
   function order_default() {
-    for (var groups = this._groups, j2 = -1, m = groups.length; ++j2 < m; ) {
-      for (var group = groups[j2], i2 = group.length - 1, next = group[i2], node; --i2 >= 0; ) {
-        if (node = group[i2]) {
-          if (next && node.compareDocumentPosition(next) ^ 4)
-            next.parentNode.insertBefore(node, next);
+    for (var groups = this._groups, j2 = -1, m2 = groups.length; ++j2 < m2; ) {
+      for (var group = groups[j2], i3 = group.length - 1, next = group[i3], node; --i3 >= 0; ) {
+        if (node = group[i3]) {
+          if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
           next = node;
         }
       }
   }
 
   // node_modules/d3-selection/src/selection/sort.js
-  function sort_default(compare) {
-    if (!compare)
-      compare = ascending2;
-    function compareNode(a, b) {
-      return a && b ? compare(a.__data__, b.__data__) : !a - !b;
+  function sort_default(compare2) {
+    if (!compare2) compare2 = ascending2;
+    function compareNode(a2, b2) {
+      return a2 && b2 ? compare2(a2.__data__, b2.__data__) : !a2 - !b2;
     }
-    for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, sortgroup = sortgroups[j2] = new Array(n2), node, i2 = 0; i2 < n2; ++i2) {
-        if (node = group[i2]) {
-          sortgroup[i2] = node;
+    for (var groups = this._groups, m2 = groups.length, sortgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, sortgroup = sortgroups[j2] = new Array(n3), node, i3 = 0; i3 < n3; ++i3) {
+        if (node = group[i3]) {
+          sortgroup[i3] = node;
         }
       }
       sortgroup.sort(compareNode);
     }
     return new Selection(sortgroups, this._parents).order();
   }
-  function ascending2(a, b) {
-    return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+  function ascending2(a2, b2) {
+    return a2 < b2 ? -1 : a2 > b2 ? 1 : a2 >= b2 ? 0 : NaN;
   }
 
   // node_modules/d3-selection/src/selection/call.js
 
   // node_modules/d3-selection/src/selection/node.js
   function node_default() {
-    for (var groups = this._groups, j2 = 0, m = groups.length; j2 < m; ++j2) {
-      for (var group = groups[j2], i2 = 0, n2 = group.length; i2 < n2; ++i2) {
-        var node = group[i2];
-        if (node)
-          return node;
+    for (var groups = this._groups, j2 = 0, m2 = groups.length; j2 < m2; ++j2) {
+      for (var group = groups[j2], i3 = 0, n3 = group.length; i3 < n3; ++i3) {
+        var node = group[i3];
+        if (node) return node;
       }
     }
     return null;
   // node_modules/d3-selection/src/selection/size.js
   function size_default() {
     let size = 0;
-    for (const node of this)
-      ++size;
+    for (const node of this) ++size;
     return size;
   }
 
 
   // node_modules/d3-selection/src/selection/each.js
   function each_default(callback) {
-    for (var groups = this._groups, j2 = 0, m = groups.length; j2 < m; ++j2) {
-      for (var group = groups[j2], i2 = 0, n2 = group.length, node; i2 < n2; ++i2) {
-        if (node = group[i2])
-          callback.call(node, node.__data__, i2, group);
+    for (var groups = this._groups, j2 = 0, m2 = groups.length; j2 < m2; ++j2) {
+      for (var group = groups[j2], i3 = 0, n3 = group.length, node; i3 < n3; ++i3) {
+        if (node = group[i3]) callback.call(node, node.__data__, i3, group);
       }
     }
     return this;
   }
   function attrFunction(name, value) {
     return function() {
-      var v = value.apply(this, arguments);
-      if (v == null)
-        this.removeAttribute(name);
-      else
-        this.setAttribute(name, v);
+      var v2 = value.apply(this, arguments);
+      if (v2 == null) this.removeAttribute(name);
+      else this.setAttribute(name, v2);
     };
   }
   function attrFunctionNS(fullname, value) {
     return function() {
-      var v = value.apply(this, arguments);
-      if (v == null)
-        this.removeAttributeNS(fullname.space, fullname.local);
-      else
-        this.setAttributeNS(fullname.space, fullname.local, v);
+      var v2 = value.apply(this, arguments);
+      if (v2 == null) this.removeAttributeNS(fullname.space, fullname.local);
+      else this.setAttributeNS(fullname.space, fullname.local, v2);
     };
   }
   function attr_default(name, value) {
   }
   function styleFunction(name, value, priority) {
     return function() {
-      var v = value.apply(this, arguments);
-      if (v == null)
-        this.style.removeProperty(name);
-      else
-        this.style.setProperty(name, v, priority);
+      var v2 = value.apply(this, arguments);
+      if (v2 == null) this.style.removeProperty(name);
+      else this.style.setProperty(name, v2, priority);
     };
   }
   function style_default(name, value, priority) {
   }
   function propertyFunction(name, value) {
     return function() {
-      var v = value.apply(this, arguments);
-      if (v == null)
-        delete this[name];
-      else
-        this[name] = v;
+      var v2 = value.apply(this, arguments);
+      if (v2 == null) delete this[name];
+      else this[name] = v2;
     };
   }
   function property_default(name, value) {
   }
   ClassList.prototype = {
     add: function(name) {
-      var i2 = this._names.indexOf(name);
-      if (i2 < 0) {
+      var i3 = this._names.indexOf(name);
+      if (i3 < 0) {
         this._names.push(name);
         this._node.setAttribute("class", this._names.join(" "));
       }
     },
     remove: function(name) {
-      var i2 = this._names.indexOf(name);
-      if (i2 >= 0) {
-        this._names.splice(i2, 1);
+      var i3 = this._names.indexOf(name);
+      if (i3 >= 0) {
+        this._names.splice(i3, 1);
         this._node.setAttribute("class", this._names.join(" "));
       }
     },
     }
   };
   function classedAdd(node, names) {
-    var list = classList(node), i2 = -1, n2 = names.length;
-    while (++i2 < n2)
-      list.add(names[i2]);
+    var list2 = classList(node), i3 = -1, n3 = names.length;
+    while (++i3 < n3) list2.add(names[i3]);
   }
   function classedRemove(node, names) {
-    var list = classList(node), i2 = -1, n2 = names.length;
-    while (++i2 < n2)
-      list.remove(names[i2]);
+    var list2 = classList(node), i3 = -1, n3 = names.length;
+    while (++i3 < n3) list2.remove(names[i3]);
   }
   function classedTrue(names) {
     return function() {
   function classed_default(name, value) {
     var names = classArray(name + "");
     if (arguments.length < 2) {
-      var list = classList(this.node()), i2 = -1, n2 = names.length;
-      while (++i2 < n2)
-        if (!list.contains(names[i2]))
-          return false;
+      var list2 = classList(this.node()), i3 = -1, n3 = names.length;
+      while (++i3 < n3) if (!list2.contains(names[i3])) return false;
       return true;
     }
     return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
   }
   function textFunction(value) {
     return function() {
-      var v = value.apply(this, arguments);
-      this.textContent = v == null ? "" : v;
+      var v2 = value.apply(this, arguments);
+      this.textContent = v2 == null ? "" : v2;
     };
   }
   function text_default(value) {
   }
   function htmlFunction(value) {
     return function() {
-      var v = value.apply(this, arguments);
-      this.innerHTML = v == null ? "" : v;
+      var v2 = value.apply(this, arguments);
+      this.innerHTML = v2 == null ? "" : v2;
     };
   }
   function html_default(value) {
 
   // node_modules/d3-selection/src/selection/raise.js
   function raise() {
-    if (this.nextSibling)
-      this.parentNode.appendChild(this);
+    if (this.nextSibling) this.parentNode.appendChild(this);
   }
   function raise_default() {
     return this.each(raise);
 
   // node_modules/d3-selection/src/selection/lower.js
   function lower() {
-    if (this.previousSibling)
-      this.parentNode.insertBefore(this, this.parentNode.firstChild);
+    if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
   }
   function lower_default() {
     return this.each(lower);
   // node_modules/d3-selection/src/selection/remove.js
   function remove() {
     var parent = this.parentNode;
-    if (parent)
-      parent.removeChild(this);
+    if (parent) parent.removeChild(this);
   }
   function remove_default() {
     return this.each(remove);
 
   // node_modules/d3-selection/src/selection/clone.js
   function selection_cloneShallow() {
-    var clone = this.cloneNode(false), parent = this.parentNode;
-    return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
+    var clone2 = this.cloneNode(false), parent = this.parentNode;
+    return parent ? parent.insertBefore(clone2, this.nextSibling) : clone2;
   }
   function selection_cloneDeep() {
-    var clone = this.cloneNode(true), parent = this.parentNode;
-    return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
+    var clone2 = this.cloneNode(true), parent = this.parentNode;
+    return parent ? parent.insertBefore(clone2, this.nextSibling) : clone2;
   }
   function clone_default(deep) {
     return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
     };
   }
   function parseTypenames2(typenames) {
-    return typenames.trim().split(/^|\s+/).map(function(t) {
-      var name = "", i2 = t.indexOf(".");
-      if (i2 >= 0)
-        name = t.slice(i2 + 1), t = t.slice(0, i2);
-      return { type: t, name };
+    return typenames.trim().split(/^|\s+/).map(function(t2) {
+      var name = "", i3 = t2.indexOf(".");
+      if (i3 >= 0) name = t2.slice(i3 + 1), t2 = t2.slice(0, i3);
+      return { type: t2, name };
     });
   }
   function onRemove(typename) {
     return function() {
       var on = this.__on;
-      if (!on)
-        return;
-      for (var j2 = 0, i2 = -1, m = on.length, o; j2 < m; ++j2) {
-        if (o = on[j2], (!typename.type || o.type === typename.type) && o.name === typename.name) {
-          this.removeEventListener(o.type, o.listener, o.options);
+      if (!on) return;
+      for (var j2 = 0, i3 = -1, m2 = on.length, o2; j2 < m2; ++j2) {
+        if (o2 = on[j2], (!typename.type || o2.type === typename.type) && o2.name === typename.name) {
+          this.removeEventListener(o2.type, o2.listener, o2.options);
         } else {
-          on[++i2] = o;
+          on[++i3] = o2;
         }
       }
-      if (++i2)
-        on.length = i2;
-      else
-        delete this.__on;
+      if (++i3) on.length = i3;
+      else delete this.__on;
     };
   }
   function onAdd(typename, value, options2) {
     return function() {
-      var on = this.__on, o, listener = contextListener(value);
-      if (on)
-        for (var j2 = 0, m = on.length; j2 < m; ++j2) {
-          if ((o = on[j2]).type === typename.type && o.name === typename.name) {
-            this.removeEventListener(o.type, o.listener, o.options);
-            this.addEventListener(o.type, o.listener = listener, o.options = options2);
-            o.value = value;
-            return;
-          }
+      var on = this.__on, o2, listener = contextListener(value);
+      if (on) for (var j2 = 0, m2 = on.length; j2 < m2; ++j2) {
+        if ((o2 = on[j2]).type === typename.type && o2.name === typename.name) {
+          this.removeEventListener(o2.type, o2.listener, o2.options);
+          this.addEventListener(o2.type, o2.listener = listener, o2.options = options2);
+          o2.value = value;
+          return;
         }
+      }
       this.addEventListener(typename.type, listener, options2);
-      o = { type: typename.type, name: typename.name, value, listener, options: options2 };
-      if (!on)
-        this.__on = [o];
-      else
-        on.push(o);
+      o2 = { type: typename.type, name: typename.name, value, listener, options: options2 };
+      if (!on) this.__on = [o2];
+      else on.push(o2);
     };
   }
   function on_default(typename, value, options2) {
-    var typenames = parseTypenames2(typename + ""), i2, n2 = typenames.length, t;
+    var typenames = parseTypenames2(typename + ""), i3, n3 = typenames.length, t2;
     if (arguments.length < 2) {
       var on = this.node().__on;
-      if (on)
-        for (var j2 = 0, m = on.length, o; j2 < m; ++j2) {
-          for (i2 = 0, o = on[j2]; i2 < n2; ++i2) {
-            if ((t = typenames[i2]).type === o.type && t.name === o.name) {
-              return o.value;
-            }
+      if (on) for (var j2 = 0, m2 = on.length, o2; j2 < m2; ++j2) {
+        for (i3 = 0, o2 = on[j2]; i3 < n3; ++i3) {
+          if ((t2 = typenames[i3]).type === o2.type && t2.name === o2.name) {
+            return o2.value;
           }
         }
+      }
       return;
     }
     on = value ? onAdd : onRemove;
-    for (i2 = 0; i2 < n2; ++i2)
-      this.each(on(typenames[i2], value, options2));
+    for (i3 = 0; i3 < n3; ++i3) this.each(on(typenames[i3], value, options2));
     return this;
   }
 
   // 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;
-      else
-        event.initEvent(type3, false, false);
+      if (params) event.initEvent(type2, params.bubbles, params.cancelable), event.detail = params.detail;
+      else event.initEvent(type2, false, false);
     }
     node.dispatchEvent(event);
   }
-  function 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
   function* iterator_default() {
-    for (var groups = this._groups, j2 = 0, m = groups.length; j2 < m; ++j2) {
-      for (var group = groups[j2], i2 = 0, n2 = group.length, node; i2 < n2; ++i2) {
-        if (node = group[i2])
-          yield node;
+    for (var groups = this._groups, j2 = 0, m2 = groups.length; j2 < m2; ++j2) {
+      for (var group = groups[j2], i3 = 0, n3 = group.length, node; i3 < n3; ++i3) {
+        if (node = group[i3]) yield node;
       }
     }
   }
   // node_modules/d3-selection/src/sourceEvent.js
   function sourceEvent_default(event) {
     let sourceEvent;
-    while (sourceEvent = event.sourceEvent)
-      event = sourceEvent;
+    while (sourceEvent = event.sourceEvent) event = sourceEvent;
     return event;
   }
 
   // node_modules/d3-selection/src/pointer.js
   function pointer_default(event, node) {
     event = sourceEvent_default(event);
-    if (node === void 0)
-      node = event.currentTarget;
+    if (node === void 0) node = event.currentTarget;
     if (node) {
       var svg2 = node.ownerSVGElement || node;
       if (svg2.createSVGPoint) {
   }
 
   // node_modules/d3-drag/src/constant.js
-  var constant_default2 = (x) => () => x;
+  var constant_default2 = (x2) => () => x2;
 
   // node_modules/d3-drag/src/event.js
-  function DragEvent(type3, {
+  function DragEvent(type2, {
     sourceEvent,
     subject,
     target,
     identifier,
     active,
-    x,
-    y,
+    x: x2,
+    y: y2,
     dx,
     dy,
-    dispatch: dispatch10
+    dispatch: dispatch14
   }) {
     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 },
       identifier: { value: identifier, enumerable: true, configurable: true },
       active: { value: active, enumerable: true, configurable: true },
-      x: { value: x, enumerable: true, configurable: true },
-      y: { value: y, enumerable: true, configurable: true },
+      x: { value: x2, enumerable: true, configurable: true },
+      y: { value: y2, enumerable: true, configurable: true },
       dx: { value: dx, enumerable: true, configurable: true },
       dy: { value: dy, enumerable: true, configurable: true },
-      _: { value: dispatch10 }
+      _: { value: dispatch14 }
     });
   }
   DragEvent.prototype.on = function() {
   function defaultContainer() {
     return this.parentNode;
   }
-  function defaultSubject(event, d) {
-    return d == null ? { x: event.x, y: event.y } : d;
+  function defaultSubject(event, d2) {
+    return d2 == null ? { x: event.x, y: event.y } : d2;
   }
   function defaultTouchable() {
     return navigator.maxTouchPoints || "ontouchstart" in this;
     function drag(selection2) {
       selection2.on("mousedown.drag", mousedowned).filter(touchable).on("touchstart.drag", touchstarted).on("touchmove.drag", touchmoved, nonpassive).on("touchend.drag touchcancel.drag", touchended).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
     }
-    function mousedowned(event, d) {
-      if (touchending || !filter2.call(this, event, d))
-        return;
-      var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
-      if (!gesture)
-        return;
+    function mousedowned(event, d2) {
+      if (touchending || !filter2.call(this, event, d2)) return;
+      var gesture = beforestart(this, container.call(this, event, d2), event, d2, "mouse");
+      if (!gesture) return;
       select_default2(event.view).on("mousemove.drag", mousemoved, nonpassivecapture).on("mouseup.drag", mouseupped, nonpassivecapture);
       nodrag_default(event.view);
       nopropagation(event);
       noevent_default(event);
       gestures.mouse("end", event);
     }
-    function touchstarted(event, d) {
-      if (!filter2.call(this, event, d))
-        return;
-      var touches = event.changedTouches, c = container.call(this, event, d), n2 = touches.length, i2, gesture;
-      for (i2 = 0; i2 < n2; ++i2) {
-        if (gesture = beforestart(this, c, event, d, touches[i2].identifier, touches[i2])) {
+    function touchstarted(event, d2) {
+      if (!filter2.call(this, event, d2)) return;
+      var touches = event.changedTouches, c2 = container.call(this, event, d2), n3 = touches.length, i3, gesture;
+      for (i3 = 0; i3 < n3; ++i3) {
+        if (gesture = beforestart(this, c2, event, d2, touches[i3].identifier, touches[i3])) {
           nopropagation(event);
-          gesture("start", event, touches[i2]);
+          gesture("start", event, touches[i3]);
         }
       }
     }
     function touchmoved(event) {
-      var touches = event.changedTouches, n2 = touches.length, i2, gesture;
-      for (i2 = 0; i2 < n2; ++i2) {
-        if (gesture = gestures[touches[i2].identifier]) {
+      var touches = event.changedTouches, n3 = touches.length, i3, gesture;
+      for (i3 = 0; i3 < n3; ++i3) {
+        if (gesture = gestures[touches[i3].identifier]) {
           noevent_default(event);
-          gesture("drag", event, touches[i2]);
+          gesture("drag", event, touches[i3]);
         }
       }
     }
     function touchended(event) {
-      var touches = event.changedTouches, n2 = touches.length, i2, gesture;
-      if (touchending)
-        clearTimeout(touchending);
+      var touches = event.changedTouches, n3 = touches.length, i3, gesture;
+      if (touchending) clearTimeout(touchending);
       touchending = setTimeout(function() {
         touchending = null;
       }, 500);
-      for (i2 = 0; i2 < n2; ++i2) {
-        if (gesture = gestures[touches[i2].identifier]) {
+      for (i3 = 0; i3 < n3; ++i3) {
+        if (gesture = gestures[touches[i3].identifier]) {
           nopropagation(event);
-          gesture("end", event, touches[i2]);
+          gesture("end", event, touches[i3]);
         }
       }
     }
-    function beforestart(that, container2, event, d, identifier, touch) {
-      var dispatch10 = listeners.copy(), p = pointer_default(touch || event, container2), dx, dy, s;
-      if ((s = subject.call(that, new DragEvent("beforestart", {
+    function beforestart(that, container2, event, d2, identifier, touch) {
+      var dispatch14 = listeners.copy(), p2 = pointer_default(touch || event, container2), dx, dy, s2;
+      if ((s2 = subject.call(that, new DragEvent("beforestart", {
         sourceEvent: event,
         target: drag,
         identifier,
         active,
-        x: p[0],
-        y: p[1],
+        x: p2[0],
+        y: p2[1],
         dx: 0,
         dy: 0,
-        dispatch: dispatch10
-      }), d)) == null)
-        return;
-      dx = s.x - p[0] || 0;
-      dy = s.y - p[1] || 0;
-      return function gesture(type3, event2, touch2) {
-        var p02 = p, n2;
-        switch (type3) {
+        dispatch: dispatch14
+      }), d2)) == null) return;
+      dx = s2.x - p2[0] || 0;
+      dy = s2.y - p2[1] || 0;
+      return function gesture(type2, event2, touch2) {
+        var p02 = p2, n3;
+        switch (type2) {
           case "start":
-            gestures[identifier] = gesture, n2 = active++;
+            gestures[identifier] = gesture, n3 = active++;
             break;
           case "end":
             delete gestures[identifier], --active;
+          // falls through
           case "drag":
-            p = pointer_default(touch2 || event2, container2), n2 = active;
+            p2 = pointer_default(touch2 || event2, container2), n3 = active;
             break;
         }
-        dispatch10.call(
-          type3,
+        dispatch14.call(
+          type2,
           that,
-          new DragEvent(type3, {
+          new DragEvent(type2, {
             sourceEvent: event2,
-            subject: s,
+            subject: s2,
             target: drag,
             identifier,
-            active: n2,
-            x: p[0] + dx,
-            y: p[1] + dy,
-            dx: p[0] - p02[0],
-            dy: p[1] - p02[1],
-            dispatch: dispatch10
+            active: n3,
+            x: p2[0] + dx,
+            y: p2[1] + dy,
+            dx: p2[0] - p02[0],
+            dy: p2[1] - p02[1],
+            dispatch: dispatch14
           }),
-          d
+          d2
         );
       };
     }
-    drag.filter = function(_) {
-      return arguments.length ? (filter2 = typeof _ === "function" ? _ : constant_default2(!!_), drag) : filter2;
+    drag.filter = function(_2) {
+      return arguments.length ? (filter2 = typeof _2 === "function" ? _2 : constant_default2(!!_2), drag) : filter2;
     };
-    drag.container = function(_) {
-      return arguments.length ? (container = typeof _ === "function" ? _ : constant_default2(_), drag) : container;
+    drag.container = function(_2) {
+      return arguments.length ? (container = typeof _2 === "function" ? _2 : constant_default2(_2), drag) : container;
     };
-    drag.subject = function(_) {
-      return arguments.length ? (subject = typeof _ === "function" ? _ : constant_default2(_), drag) : subject;
+    drag.subject = function(_2) {
+      return arguments.length ? (subject = typeof _2 === "function" ? _2 : constant_default2(_2), drag) : subject;
     };
-    drag.touchable = function(_) {
-      return arguments.length ? (touchable = typeof _ === "function" ? _ : constant_default2(!!_), drag) : touchable;
+    drag.touchable = function(_2) {
+      return arguments.length ? (touchable = typeof _2 === "function" ? _2 : constant_default2(!!_2), drag) : touchable;
     };
     drag.on = function() {
       var value = listeners.on.apply(listeners, arguments);
       return value === listeners ? drag : value;
     };
-    drag.clickDistance = function(_) {
-      return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
+    drag.clickDistance = function(_2) {
+      return arguments.length ? (clickDistance2 = (_2 = +_2) * _2, drag) : Math.sqrt(clickDistance2);
     };
     return drag;
   }
   }
   function extend(parent, definition) {
     var prototype = Object.create(parent.prototype);
-    for (var key in definition)
-      prototype[key] = definition[key];
+    for (var key in definition) prototype[key] = definition[key];
     return prototype;
   }
 
   var reN = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*";
   var reP = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
   var reHex = /^#([0-9a-f]{3,8})$/;
-  var reRgbInteger = new RegExp(`^rgb\\(${reI},${reI},${reI}\\)$`);
-  var reRgbPercent = new RegExp(`^rgb\\(${reP},${reP},${reP}\\)$`);
-  var reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`);
-  var reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`);
-  var reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`);
-  var reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`);
+  var reRgbInteger = new RegExp("^rgb\\(".concat(reI, ",").concat(reI, ",").concat(reI, "\\)$"));
+  var reRgbPercent = new RegExp("^rgb\\(".concat(reP, ",").concat(reP, ",").concat(reP, "\\)$"));
+  var reRgbaInteger = new RegExp("^rgba\\(".concat(reI, ",").concat(reI, ",").concat(reI, ",").concat(reN, "\\)$"));
+  var reRgbaPercent = new RegExp("^rgba\\(".concat(reP, ",").concat(reP, ",").concat(reP, ",").concat(reN, "\\)$"));
+  var reHslPercent = new RegExp("^hsl\\(".concat(reN, ",").concat(reP, ",").concat(reP, "\\)$"));
+  var reHslaPercent = new RegExp("^hsla\\(".concat(reN, ",").concat(reP, ",").concat(reP, ",").concat(reN, "\\)$"));
   var named = {
     aliceblue: 15792383,
     antiquewhite: 16444375,
       return this.rgb().displayable();
     },
     hex: color_formatHex,
+    // Deprecated! Use color.formatHex.
     formatHex: color_formatHex,
     formatHex8: color_formatHex8,
     formatHsl: color_formatHsl,
     return this.rgb().formatRgb();
   }
   function color(format2) {
-    var m, l;
+    var m2, l2;
     format2 = (format2 + "").trim().toLowerCase();
-    return (m = reHex.exec(format2)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) : l === 3 ? new Rgb(m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, (m & 15) << 4 | m & 15, 1) : l === 8 ? rgba(m >> 24 & 255, m >> 16 & 255, m >> 8 & 255, (m & 255) / 255) : l === 4 ? rgba(m >> 12 & 15 | m >> 8 & 240, m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, ((m & 15) << 4 | m & 15) / 255) : null) : (m = reRgbInteger.exec(format2)) ? new Rgb(m[1], m[2], m[3], 1) : (m = reRgbPercent.exec(format2)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) : (m = reRgbaInteger.exec(format2)) ? rgba(m[1], m[2], m[3], m[4]) : (m = reRgbaPercent.exec(format2)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) : (m = reHslPercent.exec(format2)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) : (m = reHslaPercent.exec(format2)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) : named.hasOwnProperty(format2) ? rgbn(named[format2]) : format2 === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
-  }
-  function rgbn(n2) {
-    return new Rgb(n2 >> 16 & 255, n2 >> 8 & 255, n2 & 255, 1);
-  }
-  function rgba(r, g, b, a) {
-    if (a <= 0)
-      r = g = b = NaN;
-    return new Rgb(r, g, b, a);
-  }
-  function rgbConvert(o) {
-    if (!(o instanceof Color))
-      o = color(o);
-    if (!o)
-      return new Rgb();
-    o = o.rgb();
-    return new Rgb(o.r, o.g, o.b, o.opacity);
-  }
-  function rgb(r, g, b, opacity) {
-    return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
-  }
-  function Rgb(r, g, b, opacity) {
-    this.r = +r;
-    this.g = +g;
-    this.b = +b;
+    return (m2 = reHex.exec(format2)) ? (l2 = m2[1].length, m2 = parseInt(m2[1], 16), l2 === 6 ? rgbn(m2) : l2 === 3 ? new Rgb(m2 >> 8 & 15 | m2 >> 4 & 240, m2 >> 4 & 15 | m2 & 240, (m2 & 15) << 4 | m2 & 15, 1) : l2 === 8 ? rgba(m2 >> 24 & 255, m2 >> 16 & 255, m2 >> 8 & 255, (m2 & 255) / 255) : l2 === 4 ? rgba(m2 >> 12 & 15 | m2 >> 8 & 240, m2 >> 8 & 15 | m2 >> 4 & 240, m2 >> 4 & 15 | m2 & 240, ((m2 & 15) << 4 | m2 & 15) / 255) : null) : (m2 = reRgbInteger.exec(format2)) ? new Rgb(m2[1], m2[2], m2[3], 1) : (m2 = reRgbPercent.exec(format2)) ? new Rgb(m2[1] * 255 / 100, m2[2] * 255 / 100, m2[3] * 255 / 100, 1) : (m2 = reRgbaInteger.exec(format2)) ? rgba(m2[1], m2[2], m2[3], m2[4]) : (m2 = reRgbaPercent.exec(format2)) ? rgba(m2[1] * 255 / 100, m2[2] * 255 / 100, m2[3] * 255 / 100, m2[4]) : (m2 = reHslPercent.exec(format2)) ? hsla(m2[1], m2[2] / 100, m2[3] / 100, 1) : (m2 = reHslaPercent.exec(format2)) ? hsla(m2[1], m2[2] / 100, m2[3] / 100, m2[4]) : named.hasOwnProperty(format2) ? rgbn(named[format2]) : format2 === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
+  }
+  function rgbn(n3) {
+    return new Rgb(n3 >> 16 & 255, n3 >> 8 & 255, n3 & 255, 1);
+  }
+  function rgba(r2, g3, b2, a2) {
+    if (a2 <= 0) r2 = g3 = b2 = NaN;
+    return new Rgb(r2, g3, b2, a2);
+  }
+  function rgbConvert(o2) {
+    if (!(o2 instanceof Color)) o2 = color(o2);
+    if (!o2) return new Rgb();
+    o2 = o2.rgb();
+    return new Rgb(o2.r, o2.g, o2.b, o2.opacity);
+  }
+  function rgb(r2, g3, b2, opacity) {
+    return arguments.length === 1 ? rgbConvert(r2) : new Rgb(r2, g3, b2, opacity == null ? 1 : opacity);
+  }
+  function Rgb(r2, g3, b2, opacity) {
+    this.r = +r2;
+    this.g = +g3;
+    this.b = +b2;
     this.opacity = +opacity;
   }
   define_default(Rgb, rgb, extend(Color, {
-    brighter(k) {
-      k = k == null ? brighter : Math.pow(brighter, k);
-      return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
+    brighter(k2) {
+      k2 = k2 == null ? brighter : Math.pow(brighter, k2);
+      return new Rgb(this.r * k2, this.g * k2, this.b * k2, this.opacity);
     },
-    darker(k) {
-      k = k == null ? darker : Math.pow(darker, k);
-      return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
+    darker(k2) {
+      k2 = k2 == null ? darker : Math.pow(darker, k2);
+      return new Rgb(this.r * k2, this.g * k2, this.b * k2, this.opacity);
     },
     rgb() {
       return this;
       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,
     toString: rgb_formatRgb
   }));
   function rgb_formatHex() {
-    return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;
+    return "#".concat(hex(this.r)).concat(hex(this.g)).concat(hex(this.b));
   }
   function rgb_formatHex8() {
-    return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;
+    return "#".concat(hex(this.r)).concat(hex(this.g)).concat(hex(this.b)).concat(hex((isNaN(this.opacity) ? 1 : this.opacity) * 255));
   }
   function rgb_formatRgb() {
-    const a = clampa(this.opacity);
-    return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`;
+    const a2 = clampa(this.opacity);
+    return "".concat(a2 === 1 ? "rgb(" : "rgba(").concat(clampi(this.r), ", ").concat(clampi(this.g), ", ").concat(clampi(this.b)).concat(a2 === 1 ? ")" : ", ".concat(a2, ")"));
   }
   function clampa(opacity) {
     return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
     value = clampi(value);
     return (value < 16 ? "0" : "") + value.toString(16);
   }
-  function hsla(h, s, l, a) {
-    if (a <= 0)
-      h = s = l = NaN;
-    else if (l <= 0 || l >= 1)
-      h = s = NaN;
-    else if (s <= 0)
-      h = NaN;
-    return new Hsl(h, s, l, a);
-  }
-  function hslConvert(o) {
-    if (o instanceof Hsl)
-      return new Hsl(o.h, o.s, o.l, o.opacity);
-    if (!(o instanceof Color))
-      o = color(o);
-    if (!o)
-      return new Hsl();
-    if (o instanceof Hsl)
-      return o;
-    o = o.rgb();
-    var r = o.r / 255, g = o.g / 255, b = o.b / 255, min3 = Math.min(r, g, b), max3 = Math.max(r, g, b), h = NaN, s = max3 - min3, l = (max3 + min3) / 2;
-    if (s) {
-      if (r === max3)
-        h = (g - b) / s + (g < b) * 6;
-      else if (g === max3)
-        h = (b - r) / s + 2;
-      else
-        h = (r - g) / s + 4;
-      s /= l < 0.5 ? max3 + min3 : 2 - max3 - min3;
-      h *= 60;
+  function hsla(h2, s2, l2, a2) {
+    if (a2 <= 0) h2 = s2 = l2 = NaN;
+    else if (l2 <= 0 || l2 >= 1) h2 = s2 = NaN;
+    else if (s2 <= 0) h2 = NaN;
+    return new Hsl(h2, s2, l2, a2);
+  }
+  function hslConvert(o2) {
+    if (o2 instanceof Hsl) return new Hsl(o2.h, o2.s, o2.l, o2.opacity);
+    if (!(o2 instanceof Color)) o2 = color(o2);
+    if (!o2) return new Hsl();
+    if (o2 instanceof Hsl) return o2;
+    o2 = o2.rgb();
+    var r2 = o2.r / 255, g3 = o2.g / 255, b2 = o2.b / 255, min3 = Math.min(r2, g3, b2), max3 = Math.max(r2, g3, b2), h2 = NaN, s2 = max3 - min3, l2 = (max3 + min3) / 2;
+    if (s2) {
+      if (r2 === max3) h2 = (g3 - b2) / s2 + (g3 < b2) * 6;
+      else if (g3 === max3) h2 = (b2 - r2) / s2 + 2;
+      else h2 = (r2 - g3) / s2 + 4;
+      s2 /= l2 < 0.5 ? max3 + min3 : 2 - max3 - min3;
+      h2 *= 60;
     } else {
-      s = l > 0 && l < 1 ? 0 : h;
+      s2 = l2 > 0 && l2 < 1 ? 0 : h2;
     }
-    return new Hsl(h, s, l, o.opacity);
+    return new Hsl(h2, s2, l2, o2.opacity);
   }
-  function hsl(h, s, l, opacity) {
-    return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
+  function hsl(h2, s2, l2, opacity) {
+    return arguments.length === 1 ? hslConvert(h2) : new Hsl(h2, s2, l2, opacity == null ? 1 : opacity);
   }
-  function Hsl(h, s, l, opacity) {
-    this.h = +h;
-    this.s = +s;
-    this.l = +l;
+  function Hsl(h2, s2, l2, opacity) {
+    this.h = +h2;
+    this.s = +s2;
+    this.l = +l2;
     this.opacity = +opacity;
   }
   define_default(Hsl, hsl, extend(Color, {
-    brighter(k) {
-      k = k == null ? brighter : Math.pow(brighter, k);
-      return new Hsl(this.h, this.s, this.l * k, this.opacity);
+    brighter(k2) {
+      k2 = k2 == null ? brighter : Math.pow(brighter, k2);
+      return new Hsl(this.h, this.s, this.l * k2, this.opacity);
     },
-    darker(k) {
-      k = k == null ? darker : Math.pow(darker, k);
-      return new Hsl(this.h, this.s, this.l * k, this.opacity);
+    darker(k2) {
+      k2 = k2 == null ? darker : Math.pow(darker, k2);
+      return new Hsl(this.h, this.s, this.l * k2, this.opacity);
     },
     rgb() {
-      var h = this.h % 360 + (this.h < 0) * 360, s = isNaN(h) || isNaN(this.s) ? 0 : this.s, l = this.l, m2 = l + (l < 0.5 ? l : 1 - l) * s, m1 = 2 * l - m2;
+      var h2 = this.h % 360 + (this.h < 0) * 360, s2 = isNaN(h2) || isNaN(this.s) ? 0 : this.s, l2 = this.l, m2 = l2 + (l2 < 0.5 ? l2 : 1 - l2) * s2, m1 = 2 * l2 - m2;
       return new Rgb(
-        hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
-        hsl2rgb(h, m1, m2),
-        hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
+        hsl2rgb(h2 >= 240 ? h2 - 240 : h2 + 120, m1, m2),
+        hsl2rgb(h2, m1, m2),
+        hsl2rgb(h2 < 120 ? h2 + 240 : h2 - 120, m1, m2),
         this.opacity
       );
     },
       return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && (0 <= this.l && this.l <= 1) && (0 <= this.opacity && this.opacity <= 1);
     },
     formatHsl() {
-      const a = clampa(this.opacity);
-      return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`;
+      const a2 = clampa(this.opacity);
+      return "".concat(a2 === 1 ? "hsl(" : "hsla(").concat(clamph(this.h), ", ").concat(clampt(this.s) * 100, "%, ").concat(clampt(this.l) * 100, "%").concat(a2 === 1 ? ")" : ", ".concat(a2, ")"));
     }
   }));
   function clamph(value) {
   function clampt(value) {
     return Math.max(0, Math.min(1, value || 0));
   }
-  function hsl2rgb(h, m1, m2) {
-    return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
+  function hsl2rgb(h2, m1, m2) {
+    return (h2 < 60 ? m1 + (m2 - m1) * h2 / 60 : h2 < 180 ? m2 : h2 < 240 ? m1 + (m2 - m1) * (240 - h2) / 60 : m1) * 255;
   }
 
   // node_modules/d3-interpolate/src/basis.js
     return ((1 - 3 * t1 + 3 * t2 - t3) * v0 + (4 - 6 * t2 + 3 * t3) * v1 + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2 + t3 * v3) / 6;
   }
   function basis_default(values) {
-    var n2 = values.length - 1;
-    return function(t) {
-      var i2 = t <= 0 ? t = 0 : t >= 1 ? (t = 1, n2 - 1) : Math.floor(t * n2), v1 = values[i2], v2 = values[i2 + 1], v0 = i2 > 0 ? values[i2 - 1] : 2 * v1 - v2, v3 = i2 < n2 - 1 ? values[i2 + 2] : 2 * v2 - v1;
-      return basis((t - i2 / n2) * n2, v0, v1, v2, v3);
+    var n3 = values.length - 1;
+    return function(t2) {
+      var i3 = t2 <= 0 ? t2 = 0 : t2 >= 1 ? (t2 = 1, n3 - 1) : Math.floor(t2 * n3), v1 = values[i3], v2 = values[i3 + 1], v0 = i3 > 0 ? values[i3 - 1] : 2 * v1 - v2, v3 = i3 < n3 - 1 ? values[i3 + 2] : 2 * v2 - v1;
+      return basis((t2 - i3 / n3) * n3, v0, v1, v2, v3);
     };
   }
 
   // node_modules/d3-interpolate/src/basisClosed.js
   function basisClosed_default(values) {
-    var n2 = values.length;
-    return function(t) {
-      var i2 = Math.floor(((t %= 1) < 0 ? ++t : t) * n2), v0 = values[(i2 + n2 - 1) % n2], v1 = values[i2 % n2], v2 = values[(i2 + 1) % n2], v3 = values[(i2 + 2) % n2];
-      return basis((t - i2 / n2) * n2, v0, v1, v2, v3);
+    var n3 = values.length;
+    return function(t2) {
+      var i3 = Math.floor(((t2 %= 1) < 0 ? ++t2 : t2) * n3), v0 = values[(i3 + n3 - 1) % n3], v1 = values[i3 % n3], v2 = values[(i3 + 1) % n3], v3 = values[(i3 + 2) % n3];
+      return basis((t2 - i3 / n3) * n3, v0, v1, v2, v3);
     };
   }
 
   // node_modules/d3-interpolate/src/constant.js
-  var constant_default3 = (x) => () => x;
+  var constant_default3 = (x2) => () => x2;
 
   // node_modules/d3-interpolate/src/color.js
-  function linear(a, d) {
-    return function(t) {
-      return a + t * d;
+  function linear(a2, d2) {
+    return function(t2) {
+      return a2 + t2 * d2;
     };
   }
-  function exponential(a, b, y) {
-    return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
-      return Math.pow(a + t * b, y);
+  function exponential(a2, b2, y2) {
+    return a2 = Math.pow(a2, y2), b2 = Math.pow(b2, y2) - a2, y2 = 1 / y2, function(t2) {
+      return Math.pow(a2 + t2 * b2, y2);
     };
   }
-  function gamma(y) {
-    return (y = +y) === 1 ? nogamma : function(a, b) {
-      return b - a ? exponential(a, b, y) : constant_default3(isNaN(a) ? b : a);
+  function gamma(y2) {
+    return (y2 = +y2) === 1 ? nogamma : function(a2, b2) {
+      return b2 - a2 ? exponential(a2, b2, y2) : constant_default3(isNaN(a2) ? b2 : a2);
     };
   }
-  function nogamma(a, b) {
-    var d = b - a;
-    return d ? linear(a, d) : constant_default3(isNaN(a) ? b : a);
+  function nogamma(a2, b2) {
+    var d2 = b2 - a2;
+    return d2 ? linear(a2, d2) : constant_default3(isNaN(a2) ? b2 : a2);
   }
 
   // node_modules/d3-interpolate/src/rgb.js
-  var rgb_default = function rgbGamma(y) {
-    var color2 = gamma(y);
+  var rgb_default = function rgbGamma(y2) {
+    var color2 = gamma(y2);
     function rgb2(start2, end) {
-      var r = color2((start2 = rgb(start2)).r, (end = rgb(end)).r), g = color2(start2.g, end.g), b = color2(start2.b, end.b), opacity = nogamma(start2.opacity, end.opacity);
-      return function(t) {
-        start2.r = r(t);
-        start2.g = g(t);
-        start2.b = b(t);
-        start2.opacity = opacity(t);
+      var r2 = color2((start2 = rgb(start2)).r, (end = rgb(end)).r), g3 = color2(start2.g, end.g), b2 = color2(start2.b, end.b), opacity = nogamma(start2.opacity, end.opacity);
+      return function(t2) {
+        start2.r = r2(t2);
+        start2.g = g3(t2);
+        start2.b = b2(t2);
+        start2.opacity = opacity(t2);
         return start2 + "";
       };
     }
   }(1);
   function rgbSpline(spline) {
     return function(colors) {
-      var n2 = colors.length, r = new Array(n2), g = new Array(n2), b = new Array(n2), i2, color2;
-      for (i2 = 0; i2 < n2; ++i2) {
-        color2 = rgb(colors[i2]);
-        r[i2] = color2.r || 0;
-        g[i2] = color2.g || 0;
-        b[i2] = color2.b || 0;
-      }
-      r = spline(r);
-      g = spline(g);
-      b = spline(b);
+      var n3 = colors.length, r2 = new Array(n3), g3 = new Array(n3), b2 = new Array(n3), i3, color2;
+      for (i3 = 0; i3 < n3; ++i3) {
+        color2 = rgb(colors[i3]);
+        r2[i3] = color2.r || 0;
+        g3[i3] = color2.g || 0;
+        b2[i3] = color2.b || 0;
+      }
+      r2 = spline(r2);
+      g3 = spline(g3);
+      b2 = spline(b2);
       color2.opacity = 1;
-      return function(t) {
-        color2.r = r(t);
-        color2.g = g(t);
-        color2.b = b(t);
+      return function(t2) {
+        color2.r = r2(t2);
+        color2.g = g3(t2);
+        color2.b = b2(t2);
         return color2 + "";
       };
     };
   var rgbBasisClosed = rgbSpline(basisClosed_default);
 
   // node_modules/d3-interpolate/src/numberArray.js
-  function numberArray_default(a, b) {
-    if (!b)
-      b = [];
-    var n2 = a ? Math.min(b.length, a.length) : 0, c = b.slice(), i2;
-    return function(t) {
-      for (i2 = 0; i2 < n2; ++i2)
-        c[i2] = a[i2] * (1 - t) + b[i2] * t;
-      return c;
+  function numberArray_default(a2, b2) {
+    if (!b2) b2 = [];
+    var n3 = a2 ? Math.min(b2.length, a2.length) : 0, c2 = b2.slice(), i3;
+    return function(t2) {
+      for (i3 = 0; i3 < n3; ++i3) c2[i3] = a2[i3] * (1 - t2) + b2[i3] * t2;
+      return c2;
     };
   }
-  function isNumberArray(x) {
-    return ArrayBuffer.isView(x) && !(x instanceof DataView);
+  function isNumberArray(x2) {
+    return ArrayBuffer.isView(x2) && !(x2 instanceof DataView);
   }
 
   // node_modules/d3-interpolate/src/array.js
-  function genericArray(a, b) {
-    var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x = new Array(na), c = new Array(nb), i2;
-    for (i2 = 0; i2 < na; ++i2)
-      x[i2] = value_default(a[i2], b[i2]);
-    for (; i2 < nb; ++i2)
-      c[i2] = b[i2];
-    return function(t) {
-      for (i2 = 0; i2 < na; ++i2)
-        c[i2] = x[i2](t);
-      return c;
+  function genericArray(a2, b2) {
+    var nb = b2 ? b2.length : 0, na = a2 ? Math.min(nb, a2.length) : 0, x2 = new Array(na), c2 = new Array(nb), i3;
+    for (i3 = 0; i3 < na; ++i3) x2[i3] = value_default(a2[i3], b2[i3]);
+    for (; i3 < nb; ++i3) c2[i3] = b2[i3];
+    return function(t2) {
+      for (i3 = 0; i3 < na; ++i3) c2[i3] = x2[i3](t2);
+      return c2;
     };
   }
 
   // node_modules/d3-interpolate/src/date.js
-  function date_default(a, b) {
-    var d = new Date();
-    return a = +a, b = +b, function(t) {
-      return d.setTime(a * (1 - t) + b * t), d;
+  function date_default(a2, b2) {
+    var d2 = /* @__PURE__ */ new Date();
+    return a2 = +a2, b2 = +b2, function(t2) {
+      return d2.setTime(a2 * (1 - t2) + b2 * t2), d2;
     };
   }
 
   // node_modules/d3-interpolate/src/number.js
-  function number_default(a, b) {
-    return a = +a, b = +b, function(t) {
-      return a * (1 - t) + b * t;
+  function number_default(a2, b2) {
+    return a2 = +a2, b2 = +b2, function(t2) {
+      return a2 * (1 - t2) + b2 * t2;
     };
   }
 
   // node_modules/d3-interpolate/src/object.js
-  function object_default(a, b) {
-    var i2 = {}, c = {}, k;
-    if (a === null || typeof a !== "object")
-      a = {};
-    if (b === null || typeof b !== "object")
-      b = {};
-    for (k in b) {
-      if (k in a) {
-        i2[k] = value_default(a[k], b[k]);
+  function object_default(a2, b2) {
+    var i3 = {}, c2 = {}, k2;
+    if (a2 === null || typeof a2 !== "object") a2 = {};
+    if (b2 === null || typeof b2 !== "object") b2 = {};
+    for (k2 in b2) {
+      if (k2 in a2) {
+        i3[k2] = value_default(a2[k2], b2[k2]);
       } else {
-        c[k] = b[k];
+        c2[k2] = b2[k2];
       }
     }
-    return function(t) {
-      for (k in i2)
-        c[k] = i2[k](t);
-      return c;
+    return function(t2) {
+      for (k2 in i3) c2[k2] = i3[k2](t2);
+      return c2;
     };
   }
 
   // node_modules/d3-interpolate/src/string.js
   var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
   var reB = new RegExp(reA.source, "g");
-  function zero2(b) {
+  function zero2(b2) {
     return function() {
-      return b;
+      return b2;
     };
   }
-  function one(b) {
-    return function(t) {
-      return b(t) + "";
+  function one(b2) {
+    return function(t2) {
+      return b2(t2) + "";
     };
   }
-  function string_default(a, b) {
-    var bi = reA.lastIndex = reB.lastIndex = 0, am, bm, bs, i2 = -1, s = [], q = [];
-    a = a + "", b = b + "";
-    while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
+  function string_default(a2, b2) {
+    var bi = reA.lastIndex = reB.lastIndex = 0, am, bm, bs, i3 = -1, s2 = [], q2 = [];
+    a2 = a2 + "", b2 = b2 + "";
+    while ((am = reA.exec(a2)) && (bm = reB.exec(b2))) {
       if ((bs = bm.index) > bi) {
-        bs = b.slice(bi, bs);
-        if (s[i2])
-          s[i2] += bs;
-        else
-          s[++i2] = bs;
+        bs = b2.slice(bi, bs);
+        if (s2[i3]) s2[i3] += bs;
+        else s2[++i3] = bs;
       }
       if ((am = am[0]) === (bm = bm[0])) {
-        if (s[i2])
-          s[i2] += bm;
-        else
-          s[++i2] = bm;
+        if (s2[i3]) s2[i3] += bm;
+        else s2[++i3] = bm;
       } else {
-        s[++i2] = null;
-        q.push({ i: i2, x: number_default(am, bm) });
+        s2[++i3] = null;
+        q2.push({ i: i3, x: number_default(am, bm) });
       }
       bi = reB.lastIndex;
     }
-    if (bi < b.length) {
-      bs = b.slice(bi);
-      if (s[i2])
-        s[i2] += bs;
-      else
-        s[++i2] = bs;
+    if (bi < b2.length) {
+      bs = b2.slice(bi);
+      if (s2[i3]) s2[i3] += bs;
+      else s2[++i3] = bs;
     }
-    return s.length < 2 ? q[0] ? one(q[0].x) : zero2(b) : (b = q.length, function(t) {
-      for (var i3 = 0, o; i3 < b; ++i3)
-        s[(o = q[i3]).i] = o.x(t);
-      return s.join("");
+    return s2.length < 2 ? q2[0] ? one(q2[0].x) : zero2(b2) : (b2 = q2.length, function(t2) {
+      for (var i4 = 0, o2; i4 < b2; ++i4) s2[(o2 = q2[i4]).i] = o2.x(t2);
+      return s2.join("");
     });
   }
 
   // node_modules/d3-interpolate/src/value.js
-  function value_default(a, b) {
-    var t = typeof b, c;
-    return b == null || t === "boolean" ? constant_default3(b) : (t === "number" ? number_default : t === "string" ? (c = color(b)) ? (b = c, rgb_default) : string_default : b instanceof color ? rgb_default : b instanceof Date ? date_default : isNumberArray(b) ? numberArray_default : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object_default : number_default)(a, b);
+  function value_default(a2, b2) {
+    var t2 = typeof b2, c2;
+    return b2 == null || t2 === "boolean" ? constant_default3(b2) : (t2 === "number" ? number_default : t2 === "string" ? (c2 = color(b2)) ? (b2 = c2, rgb_default) : string_default : b2 instanceof color ? rgb_default : b2 instanceof Date ? date_default : isNumberArray(b2) ? numberArray_default : Array.isArray(b2) ? genericArray : typeof b2.valueOf !== "function" && typeof b2.toString !== "function" || isNaN(b2) ? object_default : number_default)(a2, b2);
   }
 
   // node_modules/d3-interpolate/src/round.js
-  function round_default(a, b) {
-    return a = +a, b = +b, function(t) {
-      return Math.round(a * (1 - t) + b * t);
+  function round_default(a2, b2) {
+    return a2 = +a2, b2 = +b2, function(t2) {
+      return Math.round(a2 * (1 - t2) + b2 * t2);
     };
   }
 
     scaleX: 1,
     scaleY: 1
   };
-  function decompose_default(a, b, c, d, e, f2) {
+  function decompose_default(a2, b2, c2, d2, e3, f2) {
     var scaleX, scaleY, skewX;
-    if (scaleX = Math.sqrt(a * a + b * b))
-      a /= scaleX, b /= scaleX;
-    if (skewX = a * c + b * d)
-      c -= a * skewX, d -= b * skewX;
-    if (scaleY = Math.sqrt(c * c + d * d))
-      c /= scaleY, d /= scaleY, skewX /= scaleY;
-    if (a * d < b * c)
-      a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
+    if (scaleX = Math.sqrt(a2 * a2 + b2 * b2)) a2 /= scaleX, b2 /= scaleX;
+    if (skewX = a2 * c2 + b2 * d2) c2 -= a2 * skewX, d2 -= b2 * skewX;
+    if (scaleY = Math.sqrt(c2 * c2 + d2 * d2)) c2 /= scaleY, d2 /= scaleY, skewX /= scaleY;
+    if (a2 * d2 < b2 * c2) a2 = -a2, b2 = -b2, skewX = -skewX, scaleX = -scaleX;
     return {
-      translateX: e,
+      translateX: e3,
       translateY: f2,
-      rotate: Math.atan2(b, a) * degrees2,
+      rotate: Math.atan2(b2, a2) * degrees2,
       skewX: Math.atan(skewX) * degrees2,
       scaleX,
       scaleY
   // node_modules/d3-interpolate/src/transform/parse.js
   var svgNode;
   function parseCss(value) {
-    const m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
-    return m.isIdentity ? identity : decompose_default(m.a, m.b, m.c, m.d, m.e, m.f);
+    const m2 = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
+    return m2.isIdentity ? identity : decompose_default(m2.a, m2.b, m2.c, m2.d, m2.e, m2.f);
   }
   function parseSvg(value) {
-    if (value == null)
-      return identity;
-    if (!svgNode)
-      svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
+    if (value == null) return identity;
+    if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
     svgNode.setAttribute("transform", value);
-    if (!(value = svgNode.transform.baseVal.consolidate()))
-      return identity;
+    if (!(value = svgNode.transform.baseVal.consolidate())) return identity;
     value = value.matrix;
     return decompose_default(value.a, value.b, value.c, value.d, value.e, value.f);
   }
 
   // node_modules/d3-interpolate/src/transform/index.js
   function interpolateTransform(parse, pxComma, pxParen, degParen) {
-    function pop(s) {
-      return s.length ? s.pop() + " " : "";
+    function pop(s2) {
+      return s2.length ? s2.pop() + " " : "";
     }
-    function translate(xa, ya, xb, yb, s, q) {
+    function translate(xa, ya, xb, yb, s2, q2) {
       if (xa !== xb || ya !== yb) {
-        var i2 = s.push("translate(", null, pxComma, null, pxParen);
-        q.push({ i: i2 - 4, x: number_default(xa, xb) }, { i: i2 - 2, x: number_default(ya, yb) });
+        var i3 = s2.push("translate(", null, pxComma, null, pxParen);
+        q2.push({ i: i3 - 4, x: number_default(xa, xb) }, { i: i3 - 2, x: number_default(ya, yb) });
       } else if (xb || yb) {
-        s.push("translate(" + xb + pxComma + yb + pxParen);
+        s2.push("translate(" + xb + pxComma + yb + pxParen);
       }
     }
-    function rotate(a, b, s, q) {
-      if (a !== b) {
-        if (a - b > 180)
-          b += 360;
-        else if (b - a > 180)
-          a += 360;
-        q.push({ i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: number_default(a, b) });
-      } else if (b) {
-        s.push(pop(s) + "rotate(" + b + degParen);
+    function rotate(a2, b2, s2, q2) {
+      if (a2 !== b2) {
+        if (a2 - b2 > 180) b2 += 360;
+        else if (b2 - a2 > 180) a2 += 360;
+        q2.push({ i: s2.push(pop(s2) + "rotate(", null, degParen) - 2, x: number_default(a2, b2) });
+      } else if (b2) {
+        s2.push(pop(s2) + "rotate(" + b2 + degParen);
       }
     }
-    function skewX(a, b, s, q) {
-      if (a !== b) {
-        q.push({ i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: number_default(a, b) });
-      } else if (b) {
-        s.push(pop(s) + "skewX(" + b + degParen);
+    function skewX(a2, b2, s2, q2) {
+      if (a2 !== b2) {
+        q2.push({ i: s2.push(pop(s2) + "skewX(", null, degParen) - 2, x: number_default(a2, b2) });
+      } else if (b2) {
+        s2.push(pop(s2) + "skewX(" + b2 + degParen);
       }
     }
-    function scale(xa, ya, xb, yb, s, q) {
+    function scale(xa, ya, xb, yb, s2, q2) {
       if (xa !== xb || ya !== yb) {
-        var i2 = s.push(pop(s) + "scale(", null, ",", null, ")");
-        q.push({ i: i2 - 4, x: number_default(xa, xb) }, { i: i2 - 2, x: number_default(ya, yb) });
+        var i3 = s2.push(pop(s2) + "scale(", null, ",", null, ")");
+        q2.push({ i: i3 - 4, x: number_default(xa, xb) }, { i: i3 - 2, x: number_default(ya, yb) });
       } else if (xb !== 1 || yb !== 1) {
-        s.push(pop(s) + "scale(" + xb + "," + yb + ")");
-      }
-    }
-    return function(a, b) {
-      var s = [], q = [];
-      a = parse(a), b = parse(b);
-      translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
-      rotate(a.rotate, b.rotate, s, q);
-      skewX(a.skewX, b.skewX, s, q);
-      scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
-      a = b = null;
-      return function(t) {
-        var i2 = -1, n2 = q.length, o;
-        while (++i2 < n2)
-          s[(o = q[i2]).i] = o.x(t);
-        return s.join("");
+        s2.push(pop(s2) + "scale(" + xb + "," + yb + ")");
+      }
+    }
+    return function(a2, b2) {
+      var s2 = [], q2 = [];
+      a2 = parse(a2), b2 = parse(b2);
+      translate(a2.translateX, a2.translateY, b2.translateX, b2.translateY, s2, q2);
+      rotate(a2.rotate, b2.rotate, s2, q2);
+      skewX(a2.skewX, b2.skewX, s2, q2);
+      scale(a2.scaleX, a2.scaleY, b2.scaleX, b2.scaleY, s2, q2);
+      a2 = b2 = null;
+      return function(t2) {
+        var i3 = -1, n3 = q2.length, o2;
+        while (++i3 < n3) s2[(o2 = q2[i3]).i] = o2.x(t2);
+        return s2.join("");
       };
     };
   }
 
   // node_modules/d3-interpolate/src/zoom.js
   var epsilon22 = 1e-12;
-  function cosh(x) {
-    return ((x = Math.exp(x)) + 1 / x) / 2;
+  function cosh(x2) {
+    return ((x2 = Math.exp(x2)) + 1 / x2) / 2;
   }
-  function sinh(x) {
-    return ((x = Math.exp(x)) - 1 / x) / 2;
+  function sinh(x2) {
+    return ((x2 = Math.exp(x2)) - 1 / x2) / 2;
   }
-  function tanh(x) {
-    return ((x = Math.exp(2 * x)) - 1) / (x + 1);
+  function tanh(x2) {
+    return ((x2 = Math.exp(2 * x2)) - 1) / (x2 + 1);
   }
   var zoom_default = function zoomRho(rho, rho2, rho4) {
     function zoom(p02, p1) {
-      var ux0 = p02[0], uy0 = p02[1], w0 = p02[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i2, S;
+      var ux0 = p02[0], uy0 = p02[1], w0 = p02[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i3, S2;
       if (d2 < epsilon22) {
-        S = Math.log(w1 / w0) / rho;
-        i2 = function(t) {
+        S2 = Math.log(w1 / w0) / rho;
+        i3 = function(t2) {
           return [
-            ux0 + t * dx,
-            uy0 + t * dy,
-            w0 * Math.exp(rho * t * S)
+            ux0 + t2 * dx,
+            uy0 + t2 * dy,
+            w0 * Math.exp(rho * t2 * S2)
           ];
         };
       } else {
         var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1), b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
-        S = (r1 - r0) / rho;
-        i2 = function(t) {
-          var s = t * S, coshr0 = cosh(r0), u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
+        S2 = (r1 - r0) / rho;
+        i3 = function(t2) {
+          var s2 = t2 * S2, coshr0 = cosh(r0), u2 = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s2 + r0) - sinh(r0));
           return [
-            ux0 + u * dx,
-            uy0 + u * dy,
-            w0 * coshr0 / cosh(rho * s + r0)
+            ux0 + u2 * dx,
+            uy0 + u2 * dy,
+            w0 * coshr0 / cosh(rho * s2 + r0)
           ];
         };
       }
-      i2.duration = S * 1e3 * rho / Math.SQRT2;
-      return i2;
+      i3.duration = S2 * 1e3 * rho / Math.SQRT2;
+      return i3;
     }
-    zoom.rho = function(_) {
-      var _1 = Math.max(1e-3, +_), _2 = _1 * _1, _4 = _2 * _2;
-      return zoomRho(_1, _2, _4);
+    zoom.rho = function(_2) {
+      var _1 = Math.max(1e-3, +_2), _22 = _1 * _1, _4 = _22 * _22;
+      return zoomRho(_1, _22, _4);
     };
     return zoom;
   }(Math.SQRT2, 2, 4);
 
   // node_modules/d3-interpolate/src/quantize.js
-  function quantize_default(interpolator, n2) {
-    var samples = new Array(n2);
-    for (var i2 = 0; i2 < n2; ++i2)
-      samples[i2] = interpolator(i2 / (n2 - 1));
+  function quantize_default(interpolator, n3) {
+    var samples = new Array(n3);
+    for (var i3 = 0; i3 < n3; ++i3) samples[i3] = interpolator(i3 / (n3 - 1));
     return samples;
   }
 
   Timer.prototype = timer.prototype = {
     constructor: Timer,
     restart: function(callback, delay, time) {
-      if (typeof callback !== "function")
-        throw new TypeError("callback is not a function");
+      if (typeof callback !== "function") throw new TypeError("callback is not a function");
       time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
       if (!this._next && taskTail !== this) {
-        if (taskTail)
-          taskTail._next = this;
-        else
-          taskHead = this;
+        if (taskTail) taskTail._next = this;
+        else taskHead = this;
         taskTail = this;
       }
       this._call = callback;
     }
   };
   function timer(callback, delay, time) {
-    var t = new Timer();
-    t.restart(callback, delay, time);
-    return t;
+    var t2 = new Timer();
+    t2.restart(callback, delay, time);
+    return t2;
   }
   function timerFlush() {
     now();
     ++frame;
-    var t = taskHead, e;
-    while (t) {
-      if ((e = clockNow - t._time) >= 0)
-        t._call.call(void 0, e);
-      t = t._next;
+    var t2 = taskHead, e3;
+    while (t2) {
+      if ((e3 = clockNow - t2._time) >= 0) t2._call.call(void 0, e3);
+      t2 = t2._next;
     }
     --frame;
   }
   }
   function poke() {
     var now3 = clock.now(), delay = now3 - clockLast;
-    if (delay > pokeDelay)
-      clockSkew -= delay, clockLast = now3;
+    if (delay > pokeDelay) clockSkew -= delay, clockLast = now3;
   }
   function nap() {
     var t0, t1 = taskHead, t2, time = Infinity;
     while (t1) {
       if (t1._call) {
-        if (time > t1._time)
-          time = t1._time;
+        if (time > t1._time) time = t1._time;
         t0 = t1, t1 = t1._next;
       } else {
         t2 = t1._next, t1._next = null;
     sleep(time);
   }
   function sleep(time) {
-    if (frame)
-      return;
-    if (timeout)
-      timeout = clearTimeout(timeout);
+    if (frame) return;
+    if (timeout) timeout = clearTimeout(timeout);
     var delay = time - clockNow;
     if (delay > 24) {
-      if (time < Infinity)
-        timeout = setTimeout(wake, time - clock.now() - clockSkew);
-      if (interval)
-        interval = clearInterval(interval);
+      if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
+      if (interval) interval = clearInterval(interval);
     } else {
-      if (!interval)
-        clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
+      if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
       frame = 1, setFrame(wake);
     }
   }
 
   // node_modules/d3-timer/src/timeout.js
   function timeout_default(callback, delay, time) {
-    var t = new Timer();
+    var t2 = new Timer();
     delay = delay == null ? 0 : +delay;
-    t.restart((elapsed) => {
-      t.stop();
+    t2.restart((elapsed) => {
+      t2.stop();
       callback(elapsed + delay);
     }, delay, time);
-    return t;
+    return t2;
   }
 
   // node_modules/d3-transition/src/transition/schedule.js
   var ENDED = 6;
   function schedule_default(node, name, id2, index, group, timing) {
     var schedules = node.__transition;
-    if (!schedules)
-      node.__transition = {};
-    else if (id2 in schedules)
-      return;
+    if (!schedules) node.__transition = {};
+    else if (id2 in schedules) return;
     create(node, id2, {
       name,
       index,
+      // For context during callback.
       group,
+      // For context during callback.
       on: emptyOn,
       tween: emptyTween,
       time: timing.time,
   }
   function init(node, id2) {
     var schedule = get2(node, id2);
-    if (schedule.state > CREATED)
-      throw new Error("too late; already scheduled");
+    if (schedule.state > CREATED) throw new Error("too late; already scheduled");
     return schedule;
   }
   function set2(node, id2) {
     var schedule = get2(node, id2);
-    if (schedule.state > STARTED)
-      throw new Error("too late; already running");
+    if (schedule.state > STARTED) throw new Error("too late; already running");
     return schedule;
   }
   function get2(node, id2) {
     var schedule = node.__transition;
-    if (!schedule || !(schedule = schedule[id2]))
-      throw new Error("transition not found");
+    if (!schedule || !(schedule = schedule[id2])) throw new Error("transition not found");
     return schedule;
   }
   function create(node, id2, self2) {
     function schedule(elapsed) {
       self2.state = SCHEDULED;
       self2.timer.restart(start2, self2.delay, self2.time);
-      if (self2.delay <= elapsed)
-        start2(elapsed - self2.delay);
+      if (self2.delay <= elapsed) start2(elapsed - self2.delay);
     }
     function start2(elapsed) {
-      var i2, j2, n2, o;
-      if (self2.state !== SCHEDULED)
-        return stop();
-      for (i2 in schedules) {
-        o = schedules[i2];
-        if (o.name !== self2.name)
-          continue;
-        if (o.state === STARTED)
-          return timeout_default(start2);
-        if (o.state === RUNNING) {
-          o.state = ENDED;
-          o.timer.stop();
-          o.on.call("interrupt", node, node.__data__, o.index, o.group);
-          delete schedules[i2];
-        } else if (+i2 < id2) {
-          o.state = ENDED;
-          o.timer.stop();
-          o.on.call("cancel", node, node.__data__, o.index, o.group);
-          delete schedules[i2];
+      var i3, j2, n3, o2;
+      if (self2.state !== SCHEDULED) return stop();
+      for (i3 in schedules) {
+        o2 = schedules[i3];
+        if (o2.name !== self2.name) continue;
+        if (o2.state === STARTED) return timeout_default(start2);
+        if (o2.state === RUNNING) {
+          o2.state = ENDED;
+          o2.timer.stop();
+          o2.on.call("interrupt", node, node.__data__, o2.index, o2.group);
+          delete schedules[i3];
+        } else if (+i3 < id2) {
+          o2.state = ENDED;
+          o2.timer.stop();
+          o2.on.call("cancel", node, node.__data__, o2.index, o2.group);
+          delete schedules[i3];
         }
       }
       timeout_default(function() {
       });
       self2.state = STARTING;
       self2.on.call("start", node, node.__data__, self2.index, self2.group);
-      if (self2.state !== STARTING)
-        return;
+      if (self2.state !== STARTING) return;
       self2.state = STARTED;
-      tween = new Array(n2 = self2.tween.length);
-      for (i2 = 0, j2 = -1; i2 < n2; ++i2) {
-        if (o = self2.tween[i2].value.call(node, node.__data__, self2.index, self2.group)) {
-          tween[++j2] = o;
+      tween = new Array(n3 = self2.tween.length);
+      for (i3 = 0, j2 = -1; i3 < n3; ++i3) {
+        if (o2 = self2.tween[i3].value.call(node, node.__data__, self2.index, self2.group)) {
+          tween[++j2] = o2;
         }
       }
       tween.length = j2 + 1;
     }
     function tick(elapsed) {
-      var t = elapsed < self2.duration ? self2.ease.call(null, elapsed / self2.duration) : (self2.timer.restart(stop), self2.state = ENDING, 1), i2 = -1, n2 = tween.length;
-      while (++i2 < n2) {
-        tween[i2].call(node, t);
+      var t2 = elapsed < self2.duration ? self2.ease.call(null, elapsed / self2.duration) : (self2.timer.restart(stop), self2.state = ENDING, 1), i3 = -1, n3 = tween.length;
+      while (++i3 < n3) {
+        tween[i3].call(node, t2);
       }
       if (self2.state === ENDING) {
         self2.on.call("end", node, node.__data__, self2.index, self2.group);
       self2.state = ENDED;
       self2.timer.stop();
       delete schedules[id2];
-      for (var i2 in schedules)
-        return;
+      for (var i3 in schedules) return;
       delete node.__transition;
     }
   }
 
   // node_modules/d3-transition/src/interrupt.js
   function interrupt_default(node, name) {
-    var schedules = node.__transition, schedule, active, empty2 = true, i2;
-    if (!schedules)
-      return;
+    var schedules = node.__transition, schedule, active, empty2 = true, i3;
+    if (!schedules) return;
     name = name == null ? null : name + "";
-    for (i2 in schedules) {
-      if ((schedule = schedules[i2]).name !== name) {
+    for (i3 in schedules) {
+      if ((schedule = schedules[i3]).name !== name) {
         empty2 = false;
         continue;
       }
       schedule.state = ENDED;
       schedule.timer.stop();
       schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
-      delete schedules[i2];
+      delete schedules[i3];
     }
-    if (empty2)
-      delete node.__transition;
+    if (empty2) delete node.__transition;
   }
 
   // node_modules/d3-transition/src/selection/interrupt.js
       var schedule = set2(this, id2), tween = schedule.tween;
       if (tween !== tween0) {
         tween1 = tween0 = tween;
-        for (var i2 = 0, n2 = tween1.length; i2 < n2; ++i2) {
-          if (tween1[i2].name === name) {
+        for (var i3 = 0, n3 = tween1.length; i3 < n3; ++i3) {
+          if (tween1[i3].name === name) {
             tween1 = tween1.slice();
-            tween1.splice(i2, 1);
+            tween1.splice(i3, 1);
             break;
           }
         }
   }
   function tweenFunction(id2, name, value) {
     var tween0, tween1;
-    if (typeof value !== "function")
-      throw new Error();
+    if (typeof value !== "function") throw new Error();
     return function() {
       var schedule = set2(this, id2), tween = schedule.tween;
       if (tween !== tween0) {
         tween1 = (tween0 = tween).slice();
-        for (var t = { name, value }, i2 = 0, n2 = tween1.length; i2 < n2; ++i2) {
-          if (tween1[i2].name === name) {
-            tween1[i2] = t;
+        for (var t2 = { name, value }, i3 = 0, n3 = tween1.length; i3 < n3; ++i3) {
+          if (tween1[i3].name === name) {
+            tween1[i3] = t2;
             break;
           }
         }
-        if (i2 === n2)
-          tween1.push(t);
+        if (i3 === n3) tween1.push(t2);
       }
       schedule.tween = tween1;
     };
     name += "";
     if (arguments.length < 2) {
       var tween = get2(this.node(), id2).tween;
-      for (var i2 = 0, n2 = tween.length, t; i2 < n2; ++i2) {
-        if ((t = tween[i2]).name === name) {
-          return t.value;
+      for (var i3 = 0, n3 = tween.length, t2; i3 < n3; ++i3) {
+        if ((t2 = tween[i3]).name === name) {
+          return t2.value;
         }
       }
       return null;
   }
 
   // node_modules/d3-transition/src/transition/interpolate.js
-  function interpolate_default(a, b) {
-    var c;
-    return (typeof b === "number" ? number_default : b instanceof color ? rgb_default : (c = color(b)) ? (b = c, rgb_default) : string_default)(a, b);
+  function interpolate_default(a2, b2) {
+    var c2;
+    return (typeof b2 === "number" ? number_default : b2 instanceof color ? rgb_default : (c2 = color(b2)) ? (b2 = c2, rgb_default) : string_default)(a2, b2);
   }
 
   // node_modules/d3-transition/src/transition/attr.js
     var string00, string10, interpolate0;
     return function() {
       var string0, value1 = value(this), string1;
-      if (value1 == null)
-        return void this.removeAttribute(name);
+      if (value1 == null) return void this.removeAttribute(name);
       string0 = this.getAttribute(name);
       string1 = value1 + "";
       return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
     var string00, string10, interpolate0;
     return function() {
       var string0, value1 = value(this), string1;
-      if (value1 == null)
-        return void this.removeAttributeNS(fullname.space, fullname.local);
+      if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
       string0 = this.getAttributeNS(fullname.space, fullname.local);
       string1 = value1 + "";
       return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
     };
   }
   function attr_default2(name, value) {
-    var fullname = namespace_default(name), i2 = fullname === "transform" ? interpolateTransformSvg : interpolate_default;
-    return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS2 : attrFunction2)(fullname, i2, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS2 : attrRemove2)(fullname) : (fullname.local ? attrConstantNS2 : attrConstant2)(fullname, i2, value));
+    var fullname = namespace_default(name), i3 = fullname === "transform" ? interpolateTransformSvg : interpolate_default;
+    return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS2 : attrFunction2)(fullname, i3, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS2 : attrRemove2)(fullname) : (fullname.local ? attrConstantNS2 : attrConstant2)(fullname, i3, value));
   }
 
   // node_modules/d3-transition/src/transition/attrTween.js
-  function attrInterpolate(name, i2) {
-    return function(t) {
-      this.setAttribute(name, i2.call(this, t));
+  function attrInterpolate(name, i3) {
+    return function(t2) {
+      this.setAttribute(name, i3.call(this, t2));
     };
   }
-  function attrInterpolateNS(fullname, i2) {
-    return function(t) {
-      this.setAttributeNS(fullname.space, fullname.local, i2.call(this, t));
+  function attrInterpolateNS(fullname, i3) {
+    return function(t2) {
+      this.setAttributeNS(fullname.space, fullname.local, i3.call(this, t2));
     };
   }
   function attrTweenNS(fullname, value) {
     var t0, i0;
     function tween() {
-      var i2 = value.apply(this, arguments);
-      if (i2 !== i0)
-        t0 = (i0 = i2) && attrInterpolateNS(fullname, i2);
+      var i3 = value.apply(this, arguments);
+      if (i3 !== i0) t0 = (i0 = i3) && attrInterpolateNS(fullname, i3);
       return t0;
     }
     tween._value = value;
   function attrTween(name, value) {
     var t0, i0;
     function tween() {
-      var i2 = value.apply(this, arguments);
-      if (i2 !== i0)
-        t0 = (i0 = i2) && attrInterpolate(name, i2);
+      var i3 = value.apply(this, arguments);
+      if (i3 !== i0) t0 = (i0 = i3) && attrInterpolate(name, i3);
       return t0;
     }
     tween._value = value;
   }
   function attrTween_default(name, value) {
     var key = "attr." + name;
-    if (arguments.length < 2)
-      return (key = this.tween(key)) && key._value;
-    if (value == null)
-      return this.tween(key, null);
-    if (typeof value !== "function")
-      throw new Error();
+    if (arguments.length < 2) return (key = this.tween(key)) && key._value;
+    if (value == null) return this.tween(key, null);
+    if (typeof value !== "function") throw new Error();
     var fullname = namespace_default(name);
     return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
   }
 
   // node_modules/d3-transition/src/transition/ease.js
   function easeConstant(id2, value) {
-    if (typeof value !== "function")
-      throw new Error();
+    if (typeof value !== "function") throw new Error();
     return function() {
       set2(this, id2).ease = value;
     };
   // node_modules/d3-transition/src/transition/easeVarying.js
   function easeVarying(id2, value) {
     return function() {
-      var v = value.apply(this, arguments);
-      if (typeof v !== "function")
-        throw new Error();
-      set2(this, id2).ease = v;
+      var v2 = value.apply(this, arguments);
+      if (typeof v2 !== "function") throw new Error();
+      set2(this, id2).ease = v2;
     };
   }
   function easeVarying_default(value) {
-    if (typeof value !== "function")
-      throw new Error();
+    if (typeof value !== "function") throw new Error();
     return this.each(easeVarying(this._id, value));
   }
 
   // node_modules/d3-transition/src/transition/filter.js
   function filter_default2(match) {
-    if (typeof match !== "function")
-      match = matcher_default(match);
-    for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, subgroup = subgroups[j2] = [], node, i2 = 0; i2 < n2; ++i2) {
-        if ((node = group[i2]) && match.call(node, node.__data__, i2, group)) {
+    if (typeof match !== "function") match = matcher_default(match);
+    for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = [], node, i3 = 0; i3 < n3; ++i3) {
+        if ((node = group[i3]) && match.call(node, node.__data__, i3, group)) {
           subgroup.push(node);
         }
       }
 
   // node_modules/d3-transition/src/transition/merge.js
   function merge_default2(transition2) {
-    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) {
-        if (node = group0[i2] || group1[i2]) {
-          merge3[i2] = node;
+    if (transition2._id !== this._id) throw new Error();
+    for (var groups0 = this._groups, groups1 = transition2._groups, m0 = groups0.length, m1 = groups1.length, m2 = Math.min(m0, m1), merges = new Array(m0), j2 = 0; j2 < m2; ++j2) {
+      for (var group0 = groups0[j2], group1 = groups1[j2], n3 = group0.length, merge2 = merges[j2] = new Array(n3), node, i3 = 0; i3 < n3; ++i3) {
+        if (node = group0[i3] || group1[i3]) {
+          merge2[i3] = node;
         }
       }
     }
 
   // node_modules/d3-transition/src/transition/on.js
   function start(name) {
-    return (name + "").trim().split(/^|\s+/).every(function(t) {
-      var i2 = t.indexOf(".");
-      if (i2 >= 0)
-        t = t.slice(0, i2);
-      return !t || t === "start";
+    return (name + "").trim().split(/^|\s+/).every(function(t2) {
+      var i3 = t2.indexOf(".");
+      if (i3 >= 0) t2 = t2.slice(0, i3);
+      return !t2 || t2 === "start";
     });
   }
   function onFunction(id2, name, listener) {
     var on0, on1, sit = start(name) ? init : set2;
     return function() {
       var schedule = sit(this, id2), on = schedule.on;
-      if (on !== on0)
-        (on1 = (on0 = on).copy()).on(name, listener);
+      if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
       schedule.on = on1;
     };
   }
   function removeFunction(id2) {
     return function() {
       var parent = this.parentNode;
-      for (var i2 in this.__transition)
-        if (+i2 !== id2)
-          return;
-      if (parent)
-        parent.removeChild(this);
+      for (var i3 in this.__transition) if (+i3 !== id2) return;
+      if (parent) parent.removeChild(this);
     };
   }
   function remove_default2() {
   // node_modules/d3-transition/src/transition/select.js
   function select_default3(select) {
     var name = this._name, id2 = this._id;
-    if (typeof select !== "function")
-      select = selector_default(select);
-    for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, subgroup = subgroups[j2] = new Array(n2), node, subnode, i2 = 0; i2 < n2; ++i2) {
-        if ((node = group[i2]) && (subnode = select.call(node, node.__data__, i2, group))) {
-          if ("__data__" in node)
-            subnode.__data__ = node.__data__;
-          subgroup[i2] = subnode;
-          schedule_default(subgroup[i2], name, id2, i2, subgroup, get2(node, id2));
+    if (typeof select !== "function") select = selector_default(select);
+    for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, subgroup = subgroups[j2] = new Array(n3), node, subnode, i3 = 0; i3 < n3; ++i3) {
+        if ((node = group[i3]) && (subnode = select.call(node, node.__data__, i3, group))) {
+          if ("__data__" in node) subnode.__data__ = node.__data__;
+          subgroup[i3] = subnode;
+          schedule_default(subgroup[i3], name, id2, i3, subgroup, get2(node, id2));
         }
       }
     }
   // node_modules/d3-transition/src/transition/selectAll.js
   function selectAll_default3(select) {
     var name = this._name, id2 = this._id;
-    if (typeof select !== "function")
-      select = selectorAll_default(select);
-    for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, node, i2 = 0; i2 < n2; ++i2) {
-        if (node = group[i2]) {
-          for (var children2 = select.call(node, node.__data__, i2, group), child, inherit2 = get2(node, id2), k = 0, l = children2.length; k < l; ++k) {
-            if (child = children2[k]) {
-              schedule_default(child, name, id2, k, children2, inherit2);
+    if (typeof select !== "function") select = selectorAll_default(select);
+    for (var groups = this._groups, m2 = groups.length, subgroups = [], parents = [], j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, node, i3 = 0; i3 < n3; ++i3) {
+        if (node = group[i3]) {
+          for (var children2 = select.call(node, node.__data__, i3, group), child, inherit2 = get2(node, id2), k2 = 0, l2 = children2.length; k2 < l2; ++k2) {
+            if (child = children2[k2]) {
+              schedule_default(child, name, id2, k2, children2, inherit2);
             }
           }
           subgroups.push(children2);
     var string00, string10, interpolate0;
     return function() {
       var string0 = styleValue(this, name), value1 = value(this), string1 = value1 + "";
-      if (value1 == null)
-        string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
+      if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
       return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
     };
   }
     var on0, on1, listener0, key = "style." + name, event = "end." + key, remove2;
     return function() {
       var schedule = set2(this, id2), on = schedule.on, listener = schedule.value[key] == null ? remove2 || (remove2 = styleRemove2(name)) : void 0;
-      if (on !== on0 || listener0 !== listener)
-        (on1 = (on0 = on).copy()).on(event, listener0 = listener);
+      if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
       schedule.on = on1;
     };
   }
   function style_default2(name, value, priority) {
-    var i2 = (name += "") === "transform" ? interpolateTransformCss : interpolate_default;
-    return value == null ? this.styleTween(name, styleNull(name, i2)).on("end.style." + name, styleRemove2(name)) : typeof value === "function" ? this.styleTween(name, styleFunction2(name, i2, tweenValue(this, "style." + name, value))).each(styleMaybeRemove(this._id, name)) : this.styleTween(name, styleConstant2(name, i2, value), priority).on("end.style." + name, null);
+    var i3 = (name += "") === "transform" ? interpolateTransformCss : interpolate_default;
+    return value == null ? this.styleTween(name, styleNull(name, i3)).on("end.style." + name, styleRemove2(name)) : typeof value === "function" ? this.styleTween(name, styleFunction2(name, i3, tweenValue(this, "style." + name, value))).each(styleMaybeRemove(this._id, name)) : this.styleTween(name, styleConstant2(name, i3, value), priority).on("end.style." + name, null);
   }
 
   // node_modules/d3-transition/src/transition/styleTween.js
-  function styleInterpolate(name, i2, priority) {
-    return function(t) {
-      this.style.setProperty(name, i2.call(this, t), priority);
+  function styleInterpolate(name, i3, priority) {
+    return function(t2) {
+      this.style.setProperty(name, i3.call(this, t2), priority);
     };
   }
   function styleTween(name, value, priority) {
-    var t, i0;
+    var t2, i0;
     function tween() {
-      var i2 = value.apply(this, arguments);
-      if (i2 !== i0)
-        t = (i0 = i2) && styleInterpolate(name, i2, priority);
-      return t;
+      var i3 = value.apply(this, arguments);
+      if (i3 !== i0) t2 = (i0 = i3) && styleInterpolate(name, i3, priority);
+      return t2;
     }
     tween._value = value;
     return tween;
   }
   function styleTween_default(name, value, priority) {
     var key = "style." + (name += "");
-    if (arguments.length < 2)
-      return (key = this.tween(key)) && key._value;
-    if (value == null)
-      return this.tween(key, null);
-    if (typeof value !== "function")
-      throw new Error();
+    if (arguments.length < 2) return (key = this.tween(key)) && key._value;
+    if (value == null) return this.tween(key, null);
+    if (typeof value !== "function") throw new Error();
     return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
   }
 
   }
 
   // node_modules/d3-transition/src/transition/textTween.js
-  function textInterpolate(i2) {
-    return function(t) {
-      this.textContent = i2.call(this, t);
+  function textInterpolate(i3) {
+    return function(t2) {
+      this.textContent = i3.call(this, t2);
     };
   }
   function textTween(value) {
     var t0, i0;
     function tween() {
-      var i2 = value.apply(this, arguments);
-      if (i2 !== i0)
-        t0 = (i0 = i2) && textInterpolate(i2);
+      var i3 = value.apply(this, arguments);
+      if (i3 !== i0) t0 = (i0 = i3) && textInterpolate(i3);
       return t0;
     }
     tween._value = value;
   }
   function textTween_default(value) {
     var key = "text";
-    if (arguments.length < 1)
-      return (key = this.tween(key)) && key._value;
-    if (value == null)
-      return this.tween(key, null);
-    if (typeof value !== "function")
-      throw new Error();
+    if (arguments.length < 1) return (key = this.tween(key)) && key._value;
+    if (value == null) return this.tween(key, null);
+    if (typeof value !== "function") throw new Error();
     return this.tween(key, textTween(value));
   }
 
   // node_modules/d3-transition/src/transition/transition.js
   function transition_default() {
     var name = this._name, id0 = this._id, id1 = newId();
-    for (var groups = this._groups, m = groups.length, j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, node, i2 = 0; i2 < n2; ++i2) {
-        if (node = group[i2]) {
+    for (var groups = this._groups, m2 = groups.length, j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, node, i3 = 0; i3 < n3; ++i3) {
+        if (node = group[i3]) {
           var inherit2 = get2(node, id0);
-          schedule_default(node, name, id1, i2, group, {
+          schedule_default(node, name, id1, i3, group, {
             time: inherit2.time + inherit2.delay + inherit2.duration,
             delay: 0,
             duration: inherit2.duration,
     var on0, on1, that = this, id2 = that._id, size = that.size();
     return new Promise(function(resolve, reject) {
       var cancel = { value: reject }, end = { value: function() {
-        if (--size === 0)
-          resolve();
+        if (--size === 0) resolve();
       } };
       that.each(function() {
         var schedule = set2(this, id2), on = schedule.on;
         }
         schedule.on = on1;
       });
-      if (size === 0)
-        resolve();
+      if (size === 0) resolve();
     });
   }
 
   };
 
   // node_modules/d3-ease/src/linear.js
-  var linear2 = (t) => +t;
+  var linear2 = (t2) => +t2;
 
   // node_modules/d3-ease/src/cubic.js
-  function cubicInOut(t) {
-    return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
+  function cubicInOut(t2) {
+    return ((t2 *= 2) <= 1 ? t2 * t2 * t2 : (t2 -= 2) * t2 * t2 + 2) / 2;
   }
 
   // node_modules/d3-transition/src/selection/transition.js
   var defaultTiming = {
     time: null,
+    // Set on use.
     delay: 0,
     duration: 250,
     ease: cubicInOut
     var timing;
     while (!(timing = node.__transition) || !(timing = timing[id2])) {
       if (!(node = node.parentNode)) {
-        throw new Error(`transition ${id2} not found`);
+        throw new Error("transition ".concat(id2, " not found"));
       }
     }
     return timing;
     } else {
       id2 = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
     }
-    for (var groups = this._groups, m = groups.length, j2 = 0; j2 < m; ++j2) {
-      for (var group = groups[j2], n2 = group.length, node, i2 = 0; i2 < n2; ++i2) {
-        if (node = group[i2]) {
-          schedule_default(node, name, id2, i2, group, timing || inherit(node, id2));
+    for (var groups = this._groups, m2 = groups.length, j2 = 0; j2 < m2; ++j2) {
+      for (var group = groups[j2], n3 = group.length, node, i3 = 0; i3 < n3; ++i3) {
+        if (node = group[i3]) {
+          schedule_default(node, name, id2, i3, group, timing || inherit(node, id2));
         }
       }
     }
   selection_default.prototype.transition = transition_default2;
 
   // node_modules/d3-zoom/src/constant.js
-  var constant_default4 = (x) => () => x;
+  var constant_default4 = (x2) => () => x2;
 
   // node_modules/d3-zoom/src/event.js
-  function ZoomEvent(type3, {
+  function ZoomEvent(type2, {
     sourceEvent,
     target,
     transform: transform2,
-    dispatch: dispatch10
+    dispatch: dispatch14
   }) {
     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 },
-      _: { value: dispatch10 }
+      _: { value: dispatch14 }
     });
   }
 
   // node_modules/d3-zoom/src/transform.js
-  function Transform(k, x, y) {
-    this.k = k;
-    this.x = x;
-    this.y = y;
+  function Transform(k2, x2, y2) {
+    this.k = k2;
+    this.x = x2;
+    this.y = y2;
   }
   Transform.prototype = {
     constructor: Transform,
-    scale: function(k) {
-      return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
+    scale: function(k2) {
+      return k2 === 1 ? this : new Transform(this.k * k2, this.x, this.y);
     },
-    translate: function(x, y) {
-      return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
+    translate: function(x2, y2) {
+      return x2 === 0 & y2 === 0 ? this : new Transform(this.k, this.x + this.k * x2, this.y + this.k * y2);
     },
     apply: function(point) {
       return [point[0] * this.k + this.x, point[1] * this.k + this.y];
     },
-    applyX: function(x) {
-      return x * this.k + this.x;
+    applyX: function(x2) {
+      return x2 * this.k + this.x;
     },
-    applyY: function(y) {
-      return y * this.k + this.y;
+    applyY: function(y2) {
+      return y2 * this.k + this.y;
     },
     invert: function(location) {
       return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
     },
-    invertX: function(x) {
-      return (x - this.x) / this.k;
+    invertX: function(x2) {
+      return (x2 - this.x) / this.k;
     },
-    invertY: function(y) {
-      return (y - this.y) / this.k;
+    invertY: function(y2) {
+      return (y2 - this.y) / this.k;
     },
-    rescaleX: function(x) {
-      return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
+    rescaleX: function(x2) {
+      return x2.copy().domain(x2.range().map(this.invertX, this).map(x2.invert, x2));
     },
-    rescaleY: function(y) {
-      return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
+    rescaleY: function(y2) {
+      return y2.copy().domain(y2.range().map(this.invertY, this).map(y2.invert, y2));
     },
     toString: function() {
       return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
   var identity2 = new Transform(1, 0, 0);
   transform.prototype = Transform.prototype;
   function transform(node) {
-    while (!node.__zoom)
-      if (!(node = node.parentNode))
-        return identity2;
+    while (!node.__zoom) if (!(node = node.parentNode)) return identity2;
     return node.__zoom;
   }
 
     return (!event.ctrlKey || event.type === "wheel") && !event.button;
   }
   function defaultExtent() {
-    var e = this;
-    if (e instanceof SVGElement) {
-      e = e.ownerSVGElement || e;
-      if (e.hasAttribute("viewBox")) {
-        e = e.viewBox.baseVal;
-        return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
+    var e3 = this;
+    if (e3 instanceof SVGElement) {
+      e3 = e3.ownerSVGElement || e3;
+      if (e3.hasAttribute("viewBox")) {
+        e3 = e3.viewBox.baseVal;
+        return [[e3.x, e3.y], [e3.x + e3.width, e3.y + e3.height]];
       }
-      return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
+      return [[0, 0], [e3.width.baseVal.value, e3.height.baseVal.value]];
     }
-    return [[0, 0], [e.clientWidth, e.clientHeight]];
+    return [[0, 0], [e3.clientWidth, e3.clientHeight]];
   }
   function defaultTransform() {
     return this.__zoom || identity2;
         });
       }
     };
-    zoom.scaleBy = function(selection2, k, p, event) {
+    zoom.scaleBy = function(selection2, k2, p2, event) {
       zoom.scaleTo(selection2, function() {
-        var k0 = this.__zoom.k, k1 = typeof k === "function" ? k.apply(this, arguments) : k;
+        var k0 = this.__zoom.k, k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
         return k0 * k1;
-      }, p, event);
+      }, p2, event);
     };
-    zoom.scaleTo = function(selection2, k, p, event) {
+    zoom.scaleTo = function(selection2, k2, p2, event) {
       zoom.transform(selection2, function() {
-        var e = extent.apply(this, arguments), t0 = this.__zoom, p02 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p, p1 = t0.invert(p02), k1 = typeof k === "function" ? k.apply(this, arguments) : k;
-        return constrain(translate(scale(t0, k1), p02, p1), e, translateExtent);
-      }, p, event);
+        var e3 = extent.apply(this, arguments), t0 = this.__zoom, p02 = p2 == null ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2, p1 = t0.invert(p02), k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
+        return constrain(translate(scale(t0, k1), p02, p1), e3, translateExtent);
+      }, p2, event);
     };
-    zoom.translateBy = function(selection2, x, y, event) {
+    zoom.translateBy = function(selection2, x2, y2, event) {
       zoom.transform(selection2, function() {
         return constrain(this.__zoom.translate(
-          typeof x === "function" ? x.apply(this, arguments) : x,
-          typeof y === "function" ? y.apply(this, arguments) : y
+          typeof x2 === "function" ? x2.apply(this, arguments) : x2,
+          typeof y2 === "function" ? y2.apply(this, arguments) : y2
         ), extent.apply(this, arguments), translateExtent);
       }, null, event);
     };
-    zoom.translateTo = function(selection2, x, y, p, event) {
+    zoom.translateTo = function(selection2, x2, y2, p2, event) {
       zoom.transform(selection2, function() {
-        var e = extent.apply(this, arguments), t = this.__zoom, p02 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
-        return constrain(identity2.translate(p02[0], p02[1]).scale(t.k).translate(
-          typeof x === "function" ? -x.apply(this, arguments) : -x,
-          typeof y === "function" ? -y.apply(this, arguments) : -y
-        ), e, translateExtent);
-      }, p, event);
+        var e3 = extent.apply(this, arguments), t2 = this.__zoom, p02 = p2 == null ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2;
+        return constrain(identity2.translate(p02[0], p02[1]).scale(t2.k).translate(
+          typeof x2 === "function" ? -x2.apply(this, arguments) : -x2,
+          typeof y2 === "function" ? -y2.apply(this, arguments) : -y2
+        ), e3, translateExtent);
+      }, p2, event);
     };
-    function scale(transform2, k) {
-      k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
-      return k === transform2.k ? transform2 : new Transform(k, transform2.x, transform2.y);
+    function scale(transform2, k2) {
+      k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k2));
+      return k2 === transform2.k ? transform2 : new Transform(k2, transform2.x, transform2.y);
     }
     function translate(transform2, p02, p1) {
-      var x = p02[0] - p1[0] * transform2.k, y = p02[1] - p1[1] * transform2.k;
-      return x === transform2.x && y === transform2.y ? transform2 : new Transform(transform2.k, x, y);
+      var x2 = p02[0] - p1[0] * transform2.k, y2 = p02[1] - p1[1] * transform2.k;
+      return x2 === transform2.x && y2 === transform2.y ? transform2 : new Transform(transform2.k, x2, y2);
     }
     function centroid(extent2) {
       return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
       }).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));
-        return function(t) {
-          if (t === 1)
-            t = b;
+        var that = this, args = arguments, g3 = gesture(that, args).event(event), e3 = extent.apply(that, args), p2 = point == null ? centroid(e3) : typeof point === "function" ? point.apply(that, args) : point, w2 = Math.max(e3[1][0] - e3[0][0], e3[1][1] - e3[0][1]), a2 = that.__zoom, b2 = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i3 = interpolate(a2.invert(p2).concat(w2 / a2.k), b2.invert(p2).concat(w2 / b2.k));
+        return function(t2) {
+          if (t2 === 1) t2 = b2;
           else {
-            var l = i2(t), k = w / l[2];
-            t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
+            var l2 = i3(t2), k2 = w2 / l2[2];
+            t2 = new Transform(k2, p2[0] - l2[0] * k2, p2[1] - l2[1] * k2);
           }
-          g.zoom(null, t);
+          g3.zoom(null, t2);
         };
       });
     }
     }
     Gesture.prototype = {
       event: function(event) {
-        if (event)
-          this.sourceEvent = event;
+        if (event) this.sourceEvent = event;
         return this;
       },
       start: function() {
         return this;
       },
       zoom: function(key, transform2) {
-        if (this.mouse && key !== "mouse")
-          this.mouse[1] = transform2.invert(this.mouse[0]);
-        if (this.touch0 && key !== "touch")
-          this.touch0[1] = transform2.invert(this.touch0[0]);
-        if (this.touch1 && key !== "touch")
-          this.touch1[1] = transform2.invert(this.touch1[0]);
+        if (this.mouse && key !== "mouse") this.mouse[1] = transform2.invert(this.mouse[0]);
+        if (this.touch0 && key !== "touch") this.touch0[1] = transform2.invert(this.touch0[0]);
+        if (this.touch1 && key !== "touch") this.touch1[1] = transform2.invert(this.touch1[0]);
         this.that.__zoom = transform2;
         this.emit("zoom");
         return this;
         }
         return this;
       },
-      emit: function(type3) {
-        var d = select_default2(this.that).datum();
+      emit: function(type2) {
+        var d2 = 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
           }),
-          d
+          d2
         );
       }
     };
     function wheeled(event, ...args) {
-      if (!filter2.apply(this, arguments))
-        return;
-      var g = gesture(this, args).event(event), t = this.__zoom, k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p = pointer_default(event);
-      if (g.wheel) {
-        if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
-          g.mouse[1] = t.invert(g.mouse[0] = p);
-        }
-        clearTimeout(g.wheel);
-      } else if (t.k === k)
-        return;
+      if (!filter2.apply(this, arguments)) return;
+      var g3 = gesture(this, args).event(event), t2 = this.__zoom, k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t2.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p2 = pointer_default(event);
+      if (g3.wheel) {
+        if (g3.mouse[0][0] !== p2[0] || g3.mouse[0][1] !== p2[1]) {
+          g3.mouse[1] = t2.invert(g3.mouse[0] = p2);
+        }
+        clearTimeout(g3.wheel);
+      } else if (t2.k === k2) return;
       else {
-        g.mouse = [p, t.invert(p)];
+        g3.mouse = [p2, t2.invert(p2)];
         interrupt_default(this);
-        g.start();
+        g3.start();
       }
       noevent_default2(event);
-      g.wheel = setTimeout(wheelidled, wheelDelay);
-      g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
+      g3.wheel = setTimeout(wheelidled, wheelDelay);
+      g3.zoom("mouse", constrain(translate(scale(t2, k2), g3.mouse[0], g3.mouse[1]), g3.extent, translateExtent));
       function wheelidled() {
-        g.wheel = null;
-        g.end();
+        g3.wheel = null;
+        g3.end();
       }
     }
     function mousedowned(event, ...args) {
-      if (touchending || !filter2.apply(this, arguments))
-        return;
-      var currentTarget = event.currentTarget, g = gesture(this, args, true).event(event), v = select_default2(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), p = pointer_default(event, currentTarget), x05 = event.clientX, y05 = event.clientY;
+      if (touchending || !filter2.apply(this, arguments)) return;
+      var currentTarget = event.currentTarget, g3 = gesture(this, args, true).event(event), v2 = select_default2(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), p2 = pointer_default(event, currentTarget), x05 = event.clientX, y05 = event.clientY;
       nodrag_default(event.view);
       nopropagation2(event);
-      g.mouse = [p, this.__zoom.invert(p)];
+      g3.mouse = [p2, this.__zoom.invert(p2)];
       interrupt_default(this);
-      g.start();
+      g3.start();
       function mousemoved(event2) {
         noevent_default2(event2);
-        if (!g.moved) {
+        if (!g3.moved) {
           var dx = event2.clientX - x05, dy = event2.clientY - y05;
-          g.moved = dx * dx + dy * dy > clickDistance2;
+          g3.moved = dx * dx + dy * dy > clickDistance2;
         }
-        g.event(event2).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer_default(event2, currentTarget), g.mouse[1]), g.extent, translateExtent));
+        g3.event(event2).zoom("mouse", constrain(translate(g3.that.__zoom, g3.mouse[0] = pointer_default(event2, currentTarget), g3.mouse[1]), g3.extent, translateExtent));
       }
       function mouseupped(event2) {
-        v.on("mousemove.zoom mouseup.zoom", null);
-        yesdrag(event2.view, g.moved);
+        v2.on("mousemove.zoom mouseup.zoom", null);
+        yesdrag(event2.view, g3.moved);
         noevent_default2(event2);
-        g.event(event2).end();
+        g3.event(event2).end();
       }
     }
     function dblclicked(event, ...args) {
-      if (!filter2.apply(this, arguments))
-        return;
+      if (!filter2.apply(this, arguments)) return;
       var t0 = this.__zoom, p02 = pointer_default(event.changedTouches ? event.changedTouches[0] : event, this), p1 = t0.invert(p02), k1 = t0.k * (event.shiftKey ? 0.5 : 2), t1 = constrain(translate(scale(t0, k1), p02, p1), extent.apply(this, args), translateExtent);
       noevent_default2(event);
-      if (duration > 0)
-        select_default2(this).transition().duration(duration).call(schedule, t1, p02, event);
-      else
-        select_default2(this).call(zoom.transform, t1, p02, event);
+      if (duration > 0) select_default2(this).transition().duration(duration).call(schedule, t1, p02, event);
+      else select_default2(this).call(zoom.transform, t1, p02, event);
     }
     function touchstarted(event, ...args) {
-      if (!filter2.apply(this, arguments))
-        return;
-      var touches = event.touches, n2 = touches.length, g = gesture(this, args, event.changedTouches.length === n2).event(event), started, i2, t, p;
+      if (!filter2.apply(this, arguments)) return;
+      var touches = event.touches, n3 = touches.length, g3 = gesture(this, args, event.changedTouches.length === n3).event(event), started, i3, t2, p2;
       nopropagation2(event);
-      for (i2 = 0; i2 < n2; ++i2) {
-        t = touches[i2], p = pointer_default(t, this);
-        p = [p, this.__zoom.invert(p), t.identifier];
-        if (!g.touch0)
-          g.touch0 = p, started = true, g.taps = 1 + !!touchstarting;
-        else if (!g.touch1 && g.touch0[2] !== p[2])
-          g.touch1 = p, g.taps = 0;
-      }
-      if (touchstarting)
-        touchstarting = clearTimeout(touchstarting);
+      for (i3 = 0; i3 < n3; ++i3) {
+        t2 = touches[i3], p2 = pointer_default(t2, this);
+        p2 = [p2, this.__zoom.invert(p2), t2.identifier];
+        if (!g3.touch0) g3.touch0 = p2, started = true, g3.taps = 1 + !!touchstarting;
+        else if (!g3.touch1 && g3.touch0[2] !== p2[2]) g3.touch1 = p2, g3.taps = 0;
+      }
+      if (touchstarting) touchstarting = clearTimeout(touchstarting);
       if (started) {
-        if (g.taps < 2)
-          touchfirst = p[0], touchstarting = setTimeout(function() {
-            touchstarting = null;
-          }, touchDelay);
+        if (g3.taps < 2) touchfirst = p2[0], touchstarting = setTimeout(function() {
+          touchstarting = null;
+        }, touchDelay);
         interrupt_default(this);
-        g.start();
+        g3.start();
       }
     }
     function touchmoved(event, ...args) {
-      if (!this.__zooming)
-        return;
-      var g = gesture(this, args).event(event), touches = event.changedTouches, n2 = touches.length, i2, t, p, l;
+      if (!this.__zooming) return;
+      var g3 = gesture(this, args).event(event), touches = event.changedTouches, n3 = touches.length, i3, t2, p2, l2;
       noevent_default2(event);
-      for (i2 = 0; i2 < n2; ++i2) {
-        t = touches[i2], p = pointer_default(t, this);
-        if (g.touch0 && g.touch0[2] === t.identifier)
-          g.touch0[0] = p;
-        else if (g.touch1 && g.touch1[2] === t.identifier)
-          g.touch1[0] = p;
-      }
-      t = g.that.__zoom;
-      if (g.touch1) {
-        var p02 = g.touch0[0], l0 = g.touch0[1], p1 = g.touch1[0], l1 = g.touch1[1], dp = (dp = p1[0] - p02[0]) * dp + (dp = p1[1] - p02[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
-        t = scale(t, Math.sqrt(dp / dl));
-        p = [(p02[0] + p1[0]) / 2, (p02[1] + p1[1]) / 2];
-        l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
-      } else if (g.touch0)
-        p = g.touch0[0], l = g.touch0[1];
-      else
-        return;
-      g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
+      for (i3 = 0; i3 < n3; ++i3) {
+        t2 = touches[i3], p2 = pointer_default(t2, this);
+        if (g3.touch0 && g3.touch0[2] === t2.identifier) g3.touch0[0] = p2;
+        else if (g3.touch1 && g3.touch1[2] === t2.identifier) g3.touch1[0] = p2;
+      }
+      t2 = g3.that.__zoom;
+      if (g3.touch1) {
+        var p02 = g3.touch0[0], l0 = g3.touch0[1], p1 = g3.touch1[0], l1 = g3.touch1[1], dp = (dp = p1[0] - p02[0]) * dp + (dp = p1[1] - p02[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
+        t2 = scale(t2, Math.sqrt(dp / dl));
+        p2 = [(p02[0] + p1[0]) / 2, (p02[1] + p1[1]) / 2];
+        l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
+      } else if (g3.touch0) p2 = g3.touch0[0], l2 = g3.touch0[1];
+      else return;
+      g3.zoom("touch", constrain(translate(t2, p2, l2), g3.extent, translateExtent));
     }
     function touchended(event, ...args) {
-      if (!this.__zooming)
-        return;
-      var g = gesture(this, args).event(event), touches = event.changedTouches, n2 = touches.length, i2, t;
+      if (!this.__zooming) return;
+      var g3 = gesture(this, args).event(event), touches = event.changedTouches, n3 = touches.length, i3, t2;
       nopropagation2(event);
-      if (touchending)
-        clearTimeout(touchending);
+      if (touchending) clearTimeout(touchending);
       touchending = setTimeout(function() {
         touchending = null;
       }, touchDelay);
-      for (i2 = 0; i2 < n2; ++i2) {
-        t = touches[i2];
-        if (g.touch0 && g.touch0[2] === t.identifier)
-          delete g.touch0;
-        else if (g.touch1 && g.touch1[2] === t.identifier)
-          delete g.touch1;
-      }
-      if (g.touch1 && !g.touch0)
-        g.touch0 = g.touch1, delete g.touch1;
-      if (g.touch0)
-        g.touch0[1] = this.__zoom.invert(g.touch0[0]);
+      for (i3 = 0; i3 < n3; ++i3) {
+        t2 = touches[i3];
+        if (g3.touch0 && g3.touch0[2] === t2.identifier) delete g3.touch0;
+        else if (g3.touch1 && g3.touch1[2] === t2.identifier) delete g3.touch1;
+      }
+      if (g3.touch1 && !g3.touch0) g3.touch0 = g3.touch1, delete g3.touch1;
+      if (g3.touch0) g3.touch0[1] = this.__zoom.invert(g3.touch0[0]);
       else {
-        g.end();
-        if (g.taps === 2) {
-          t = pointer_default(t, this);
-          if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
-            var p = select_default2(this).on("dblclick.zoom");
-            if (p)
-              p.apply(this, arguments);
+        g3.end();
+        if (g3.taps === 2) {
+          t2 = pointer_default(t2, this);
+          if (Math.hypot(touchfirst[0] - t2[0], touchfirst[1] - t2[1]) < tapDistance) {
+            var p2 = select_default2(this).on("dblclick.zoom");
+            if (p2) p2.apply(this, arguments);
           }
         }
       }
     }
-    zoom.wheelDelta = function(_) {
-      return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant_default4(+_), zoom) : wheelDelta;
+    zoom.wheelDelta = function(_2) {
+      return arguments.length ? (wheelDelta = typeof _2 === "function" ? _2 : constant_default4(+_2), zoom) : wheelDelta;
     };
-    zoom.filter = function(_) {
-      return arguments.length ? (filter2 = typeof _ === "function" ? _ : constant_default4(!!_), zoom) : filter2;
+    zoom.filter = function(_2) {
+      return arguments.length ? (filter2 = typeof _2 === "function" ? _2 : constant_default4(!!_2), zoom) : filter2;
     };
-    zoom.touchable = function(_) {
-      return arguments.length ? (touchable = typeof _ === "function" ? _ : constant_default4(!!_), zoom) : touchable;
+    zoom.touchable = function(_2) {
+      return arguments.length ? (touchable = typeof _2 === "function" ? _2 : constant_default4(!!_2), zoom) : touchable;
     };
-    zoom.extent = function(_) {
-      return arguments.length ? (extent = typeof _ === "function" ? _ : constant_default4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
+    zoom.extent = function(_2) {
+      return arguments.length ? (extent = typeof _2 === "function" ? _2 : constant_default4([[+_2[0][0], +_2[0][1]], [+_2[1][0], +_2[1][1]]]), zoom) : extent;
     };
-    zoom.scaleExtent = function(_) {
-      return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
+    zoom.scaleExtent = function(_2) {
+      return arguments.length ? (scaleExtent[0] = +_2[0], scaleExtent[1] = +_2[1], zoom) : [scaleExtent[0], scaleExtent[1]];
     };
-    zoom.translateExtent = function(_) {
-      return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
+    zoom.translateExtent = function(_2) {
+      return arguments.length ? (translateExtent[0][0] = +_2[0][0], translateExtent[1][0] = +_2[1][0], translateExtent[0][1] = +_2[0][1], translateExtent[1][1] = +_2[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
     };
-    zoom.constrain = function(_) {
-      return arguments.length ? (constrain = _, zoom) : constrain;
+    zoom.constrain = function(_2) {
+      return arguments.length ? (constrain = _2, zoom) : constrain;
     };
-    zoom.duration = function(_) {
-      return arguments.length ? (duration = +_, zoom) : duration;
+    zoom.duration = function(_2) {
+      return arguments.length ? (duration = +_2, zoom) : duration;
     };
-    zoom.interpolate = function(_) {
-      return arguments.length ? (interpolate = _, zoom) : interpolate;
+    zoom.interpolate = function(_2) {
+      return arguments.length ? (interpolate = _2, zoom) : interpolate;
     };
     zoom.on = function() {
       var value = listeners.on.apply(listeners, arguments);
       return value === listeners ? zoom : value;
     };
-    zoom.clickDistance = function(_) {
-      return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
+    zoom.clickDistance = function(_2) {
+      return arguments.length ? (clickDistance2 = (_2 = +_2) * _2, zoom) : Math.sqrt(clickDistance2);
     };
-    zoom.tapDistance = function(_) {
-      return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
+    zoom.tapDistance = function(_2) {
+      return arguments.length ? (tapDistance = +_2, zoom) : tapDistance;
     };
     return zoom;
   }
   // modules/geo/raw_mercator.js
   function geoRawMercator() {
     var project = mercatorRaw;
-    var k = 512 / Math.PI;
-    var x = 0;
-    var y = 0;
+    var k2 = 512 / Math.PI;
+    var x2 = 0;
+    var y2 = 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];
+      return [point[0] * k2 + x2, y2 - point[1] * k2];
     }
     projection2.invert = function(point) {
-      point = project.invert((point[0] - x) / k, (y - point[1]) / k);
+      point = project.invert((point[0] - x2) / k2, (y2 - point[1]) / k2);
       return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
     };
-    projection2.scale = function(_) {
-      if (!arguments.length)
-        return k;
-      k = +_;
+    projection2.scale = function(_2) {
+      if (!arguments.length) return k2;
+      k2 = +_2;
       return projection2;
     };
-    projection2.translate = function(_) {
-      if (!arguments.length)
-        return [x, y];
-      x = +_[0];
-      y = +_[1];
+    projection2.translate = function(_2) {
+      if (!arguments.length) return [x2, y2];
+      x2 = +_2[0];
+      y2 = +_2[1];
       return projection2;
     };
-    projection2.clipExtent = function(_) {
-      if (!arguments.length)
-        return clipExtent;
-      clipExtent = _;
+    projection2.clipExtent = function(_2) {
+      if (!arguments.length) return clipExtent;
+      clipExtent = _2;
       return projection2;
     };
     projection2.transform = function(obj) {
-      if (!arguments.length)
-        return identity2.translate(x, y).scale(k);
-      x = +obj.x;
-      y = +obj.y;
-      k = +obj.k;
+      if (!arguments.length) return identity2.translate(x2, y2).scale(k2);
+      x2 = +obj.x;
+      y2 = +obj.y;
+      k2 = +obj.k;
       return projection2;
     };
     projection2.stream = transform_default({
-      point: function(x2, y2) {
-        var vec = projection2([x2, y2]);
+      point: function(x3, y3) {
+        var vec = projection2([x3, y3]);
         this.stream.point(vec[0], vec[1]);
       }
     }).stream;
   }
 
   // modules/geo/ortho.js
-  function geoOrthoNormalizedDotProduct(a, b, origin) {
-    if (geoVecEqual(origin, a) || geoVecEqual(origin, b)) {
+  function geoOrthoNormalizedDotProduct(a2, b2, origin) {
+    if (geoVecEqual(origin, a2) || geoVecEqual(origin, b2)) {
       return 1;
     }
-    return geoVecNormalizedDot(a, b, origin);
+    return geoVecNormalizedDot(a2, b2, origin);
   }
   function geoOrthoFilterDotProduct(dotp, epsilon3, lowerThreshold, upperThreshold, allowStraightAngles) {
     var val = Math.abs(dotp);
     var score = 0;
     var first = isClosed ? 0 : 1;
     var last = isClosed ? points.length : points.length - 1;
-    var coords = points.map(function(p) {
-      return p.coord;
+    var coords = points.map(function(p2) {
+      return p2.coord;
     });
     var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
     var upperThreshold = Math.cos(threshold * Math.PI / 180);
-    for (var i2 = first; i2 < last; i2++) {
-      var a = coords[(i2 - 1 + coords.length) % coords.length];
-      var origin = coords[i2];
-      var b = coords[(i2 + 1) % coords.length];
-      var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon3, lowerThreshold, upperThreshold);
-      if (dotp === null)
-        continue;
+    for (var i3 = first; i3 < last; i3++) {
+      var a2 = coords[(i3 - 1 + coords.length) % coords.length];
+      var origin = coords[i3];
+      var b2 = coords[(i3 + 1) % coords.length];
+      var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a2, b2, origin), epsilon3, lowerThreshold, upperThreshold);
+      if (dotp === null) continue;
       score = score + 2 * Math.min(Math.abs(dotp - 1), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
     }
     return score;
     var max3 = -Infinity;
     var first = isClosed ? 0 : 1;
     var last = isClosed ? coords.length : coords.length - 1;
-    for (var i2 = first; i2 < last; i2++) {
-      var a = coords[(i2 - 1 + coords.length) % coords.length];
-      var origin = coords[i2];
-      var b = coords[(i2 + 1) % coords.length];
-      var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin);
+    for (var i3 = first; i3 < last; i3++) {
+      var a2 = coords[(i3 - 1 + coords.length) % coords.length];
+      var origin = coords[i3];
+      var b2 = coords[(i3 + 1) % coords.length];
+      var normalizedDotP = geoOrthoNormalizedDotProduct(a2, b2, origin);
       var angle2 = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
-      if (angle2 > 45)
-        angle2 = 90 - angle2;
-      if (angle2 >= lessThan)
-        continue;
-      if (angle2 > max3)
-        max3 = angle2;
+      if (angle2 > 45) angle2 = 90 - angle2;
+      if (angle2 >= lessThan) continue;
+      if (angle2 > max3) max3 = angle2;
     }
-    if (max3 === -Infinity)
-      return null;
+    if (max3 === -Infinity) return null;
     return max3;
   }
   function geoOrthoCanOrthogonalize(coords, isClosed, epsilon3, threshold, allowStraightAngles) {
     var last = isClosed ? coords.length : coords.length - 1;
     var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
     var upperThreshold = Math.cos(threshold * Math.PI / 180);
-    for (var i2 = first; i2 < last; i2++) {
-      var a = coords[(i2 - 1 + coords.length) % coords.length];
-      var origin = coords[i2];
-      var b = coords[(i2 + 1) % coords.length];
-      var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon3, lowerThreshold, upperThreshold, allowStraightAngles);
-      if (dotp === null)
-        continue;
-      if (Math.abs(dotp) > 0)
-        return 1;
+    for (var i3 = first; i3 < last; i3++) {
+      var a2 = coords[(i3 - 1 + coords.length) % coords.length];
+      var origin = coords[i3];
+      var b2 = coords[(i3 + 1) % coords.length];
+      var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a2, b2, origin), epsilon3, lowerThreshold, upperThreshold, allowStraightAngles);
+      if (dotp === null) continue;
+      if (Math.abs(dotp) > 0) return 1;
       score = 0;
     }
     return score;
   }
 
-  // modules/util/array.js
-  function utilArrayIdentical(a, b) {
-    if (a === b)
-      return true;
-    var i2 = a.length;
-    if (i2 !== b.length)
+  // 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 && // purposely exclude colon
+    key.indexOf("tiger:") !== 0;
+  }
+  var osmLifecyclePrefixes = {
+    // nonexistent, might be built
+    proposed: true,
+    planned: true,
+    // under maintenance 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) {
+    const keySegments = key.split(":");
+    if (keySegments.length === 1) return key;
+    if (keySegments[0] in osmLifecyclePrefixes) {
+      return key.slice(keySegments[0].length + 1);
+    }
+    return key;
+  }
+  var osmAreaKeys = {};
+  function osmSetAreaKeys(value) {
+    osmAreaKeys = value;
+  }
+  var osmAreaKeysExceptions = {
+    highway: {
+      elevator: true,
+      rest_area: true,
+      services: true
+    },
+    public_transport: {
+      platform: true
+    },
+    railway: {
+      platform: true,
+      roundhouse: true,
+      station: true,
+      traverser: true,
+      turntable: true,
+      wash: true,
+      ventilation_shaft: true
+    },
+    waterway: {
+      dam: true
+    },
+    amenity: {
+      bicycle_parking: true
+    }
+  };
+  function osmTagSuggestingArea(tags) {
+    if (tags.area === "yes") return { area: "yes" };
+    if (tags.area === "no") return null;
+    var returnTags = {};
+    for (var realKey in tags) {
+      const key = osmRemoveLifecyclePrefix(realKey);
+      if (key in osmAreaKeys && !(tags[realKey] in osmAreaKeys[key])) {
+        returnTags[realKey] = tags[realKey];
+        return returnTags;
+      }
+      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;
+  }
+  var osmVertexTags = {};
+  function osmSetVertexTags(value) {
+    osmVertexTags = value;
+  }
+  function osmNodeGeometriesForTags(nodeTags) {
+    var geometries = {};
+    for (var key in nodeTags) {
+      if (osmPointTags[key] && (osmPointTags[key]["*"] || osmPointTags[key][nodeTags[key]])) {
+        geometries.point = true;
+      }
+      if (osmVertexTags[key] && (osmVertexTags[key]["*"] || osmVertexTags[key][nodeTags[key]])) {
+        geometries.vertex = true;
+      }
+      if (geometries.point && geometries.vertex) break;
+    }
+    return geometries;
+  }
+  var osmOneWayTags = {
+    "aerialway": {
+      "chair_lift": true,
+      "drag_lift": true,
+      "j-bar": true,
+      "magic_carpet": true,
+      "mixed_lift": true,
+      "platter": true,
+      "rope_tow": true,
+      "t-bar": true,
+      "zip_line": true
+    },
+    "conveying": {
+      "forward": true,
+      "backward": true,
+      "reversible": true
+    },
+    "highway": {
+      "motorway": true
+    },
+    "junction": {
+      "circular": true,
+      "roundabout": true
+    },
+    "man_made": {
+      "goods_conveyor": true,
+      "piste:halfpipe": true
+    },
+    "piste:type": {
+      "downhill": true,
+      "sled": true,
+      "yes": true
+    },
+    "seamark:type": {
+      "two-way_route": true,
+      "recommended_traffic_lane": true,
+      "separation_lane": true,
+      "separation_roundabout": true
+    },
+    "waterway": {
+      "canal": true,
+      "ditch": true,
+      "drain": true,
+      "fish_pass": true,
+      "flowline": true,
+      "pressurised": true,
+      "river": true,
+      "spillway": true,
+      "stream": true,
+      "tidal_channel": true
+    }
+  };
+  var osmPavedTags = {
+    "surface": {
+      "paved": true,
+      "asphalt": true,
+      "concrete": true,
+      "chipseal": true,
+      "concrete:lanes": true,
+      "concrete:plates": true
+    },
+    "tracktype": {
+      "grade1": true
+    }
+  };
+  var osmSemipavedTags = {
+    "surface": {
+      "cobblestone": true,
+      "cobblestone:flattened": true,
+      "unhewn_cobblestone": true,
+      "sett": true,
+      "paving_stones": true,
+      "metal": true,
+      "wood": true
+    }
+  };
+  var osmRightSideIsInsideTags = {
+    "natural": {
+      "cliff": true,
+      "coastline": "coastline"
+    },
+    "barrier": {
+      "retaining_wall": true,
+      "kerb": true,
+      "guard_rail": true,
+      "city_wall": true
+    },
+    "man_made": {
+      "embankment": true,
+      "quay": true
+    },
+    "waterway": {
+      "weir": true
+    }
+  };
+  var osmRoutableHighwayTagValues = {
+    motorway: true,
+    trunk: true,
+    primary: true,
+    secondary: true,
+    tertiary: true,
+    residential: true,
+    motorway_link: true,
+    trunk_link: true,
+    primary_link: true,
+    secondary_link: true,
+    tertiary_link: true,
+    unclassified: true,
+    road: true,
+    service: true,
+    track: true,
+    living_street: true,
+    bus_guideway: true,
+    busway: true,
+    path: true,
+    footway: true,
+    cycleway: true,
+    bridleway: true,
+    pedestrian: true,
+    corridor: true,
+    steps: true,
+    ladder: true
+  };
+  var osmPathHighwayTagValues = {
+    path: true,
+    footway: true,
+    cycleway: true,
+    bridleway: true,
+    pedestrian: true,
+    corridor: true,
+    steps: true,
+    ladder: true
+  };
+  var osmRailwayTrackTagValues = {
+    rail: true,
+    light_rail: true,
+    tram: true,
+    subway: true,
+    monorail: true,
+    funicular: true,
+    miniature: true,
+    narrow_gauge: true,
+    disused: true,
+    preserved: true
+  };
+  var osmFlowingWaterwayTagValues = {
+    canal: true,
+    ditch: true,
+    drain: true,
+    fish_pass: true,
+    flowline: true,
+    river: 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/;
+  function isColourValid(value) {
+    if (!value.match(/^(#([0-9a-fA-F]{3}){1,2}|\w+)$/)) {
       return false;
-    while (i2--) {
-      if (a[i2] !== b[i2])
-        return false;
+    }
+    if (!CSS.supports("color", value) || ["unset", "inherit", "initial", "revert"].includes(value)) {
+      return false;
+    }
+    return true;
+  }
+  var osmMutuallyExclusiveTagPairs = [
+    ["noname", "name"],
+    ["noref", "ref"],
+    ["nohousenumber", "addr:housenumber"],
+    ["noaddress", "addr:housenumber"],
+    ["noaddress", "addr:housename"],
+    ["noaddress", "addr:unit"],
+    ["addr:nostreet", "addr:street"]
+  ];
+
+  // modules/util/array.js
+  function utilArrayIdentical(a2, b2) {
+    if (a2 === b2) return true;
+    var i3 = a2.length;
+    if (i3 !== b2.length) return false;
+    while (i3--) {
+      if (a2[i3] !== b2[i3]) return false;
     }
     return true;
   }
-  function utilArrayDifference(a, b) {
-    var other = new Set(b);
-    return Array.from(new Set(a)).filter(function(v) {
-      return !other.has(v);
+  function utilArrayDifference(a2, b2) {
+    var other = new Set(b2);
+    return Array.from(new Set(a2)).filter(function(v2) {
+      return !other.has(v2);
     });
   }
-  function utilArrayIntersection(a, b) {
-    var other = new Set(b);
-    return Array.from(new Set(a)).filter(function(v) {
-      return other.has(v);
+  function utilArrayIntersection(a2, b2) {
+    var other = new Set(b2);
+    return Array.from(new Set(a2)).filter(function(v2) {
+      return other.has(v2);
     });
   }
-  function utilArrayUnion(a, b) {
-    var result = new Set(a);
-    b.forEach(function(v) {
-      result.add(v);
+  function utilArrayUnion(a2, b2) {
+    var result = new Set(a2);
+    b2.forEach(function(v2) {
+      result.add(v2);
     });
     return Array.from(result);
   }
-  function utilArrayUniq(a) {
-    return Array.from(new Set(a));
+  function utilArrayUniq(a2) {
+    return Array.from(new Set(a2));
   }
-  function utilArrayChunk(a, chunkSize) {
-    if (!chunkSize || chunkSize < 0)
-      return [a.slice()];
-    var result = new Array(Math.ceil(a.length / chunkSize));
-    return Array.from(result, function(item, i2) {
-      return a.slice(i2 * chunkSize, i2 * chunkSize + chunkSize);
+  function utilArrayChunk(a2, chunkSize) {
+    if (!chunkSize || chunkSize < 0) return [a2.slice()];
+    var result = new Array(Math.ceil(a2.length / chunkSize));
+    return Array.from(result, function(item, i3) {
+      return a2.slice(i3 * chunkSize, i3 * chunkSize + chunkSize);
     });
   }
-  function utilArrayFlatten(a) {
-    return a.reduce(function(acc, val) {
+  function utilArrayFlatten(a2) {
+    return a2.reduce(function(acc, val) {
       return acc.concat(val);
     }, []);
   }
-  function utilArrayGroupBy(a, key) {
-    return a.reduce(function(acc, item) {
+  function utilArrayGroupBy(a2, key) {
+    return a2.reduce(function(acc, item) {
       var group = typeof key === "function" ? key(item) : item[key];
       (acc[group] = acc[group] || []).push(item);
       return acc;
     }, {});
   }
-  function utilArrayUniqBy(a, key) {
+  function utilArrayUniqBy(a2, key) {
     var seen = /* @__PURE__ */ new Set();
-    return a.reduce(function(acc, item) {
+    return a2.reduce(function(acc, item) {
       var val = typeof key === "function" ? key(item) : item[key];
       if (val && !seen.has(val)) {
         seen.add(val);
     if (arabicRegex.test(inputText)) {
       inputText = (0, import_alif_toolkit.WordShaper)(inputText);
     }
-    for (var n2 = 0; n2 < inputText.length; n2++) {
-      var c = inputText[n2];
-      if (arabicMath.test(c)) {
+    for (var n3 = 0; n3 < inputText.length; n3++) {
+      var c2 = inputText[n3];
+      if (arabicMath.test(c2)) {
         ret += rtlBuffer.reverse().join("");
-        rtlBuffer = [c];
+        rtlBuffer = [c2];
       } else {
         if (rtlBuffer.length && arabicMath.test(rtlBuffer[rtlBuffer.length - 1])) {
           ret += rtlBuffer.reverse().join("");
           rtlBuffer = [];
         }
-        if ((thaanaVowel.test(c) || hebrewSign.test(c) || arabicDiacritics.test(c)) && rtlBuffer.length) {
-          rtlBuffer[rtlBuffer.length - 1] += c;
-        } else if (rtlRegex.test(c) || c.charCodeAt(0) >= 64336 && c.charCodeAt(0) <= 65023 || c.charCodeAt(0) >= 65136 && c.charCodeAt(0) <= 65279) {
-          rtlBuffer.push(c);
-        } else if (c === " " && rtlBuffer.length) {
+        if ((thaanaVowel.test(c2) || hebrewSign.test(c2) || arabicDiacritics.test(c2)) && rtlBuffer.length) {
+          rtlBuffer[rtlBuffer.length - 1] += c2;
+        } else if (rtlRegex.test(c2) || c2.charCodeAt(0) >= 64336 && c2.charCodeAt(0) <= 65023 || c2.charCodeAt(0) >= 65136 && c2.charCodeAt(0) <= 65279) {
+          rtlBuffer.push(c2);
+        } else if (c2 === " " && rtlBuffer.length) {
           rtlBuffer = [rtlBuffer.reverse().join("") + " "];
         } else {
-          ret += rtlBuffer.reverse().join("") + c;
+          ret += rtlBuffer.reverse().join("") + c2;
           rtlBuffer = [];
         }
       }
   var _storage;
   try {
     _storage = localStorage;
-  } catch (e) {
+  } catch {
   }
-  _storage = _storage || (() => {
-    let s = {};
+  _storage = _storage || /* @__PURE__ */ (() => {
+    let s2 = {};
     return {
-      getItem: (k) => s[k],
-      setItem: (k, v) => s[k] = v,
-      removeItem: (k) => delete s[k]
+      getItem: (k2) => s2[k2],
+      setItem: (k2, v2) => s2[k2] = v2,
+      removeItem: (k2) => delete s2[k2]
     };
   })();
   var _listeners = {};
-  function corePreferences(k, v) {
+  function corePreferences(k2, v2) {
     try {
-      if (v === void 0)
-        return _storage.getItem(k);
-      else if (v === null)
-        _storage.removeItem(k);
-      else
-        _storage.setItem(k, v);
-      if (_listeners[k]) {
-        _listeners[k].forEach((handler) => handler(v));
+      if (v2 === void 0) return _storage.getItem(k2);
+      else if (v2 === null) _storage.removeItem(k2);
+      else _storage.setItem(k2, v2);
+      if (_listeners[k2]) {
+        _listeners[k2].forEach((handler) => handler(v2));
       }
       return true;
-    } catch (e) {
+    } catch {
       if (typeof console !== "undefined") {
         console.error("localStorage quota exceeded");
       }
       return false;
     }
   }
-  corePreferences.onChange = function(k, handler) {
-    _listeners[k] = _listeners[k] || [];
-    _listeners[k].push(handler);
+  corePreferences.onChange = function(k2, handler) {
+    _listeners[k2] = _listeners[k2] || [];
+    _listeners[k2].push(handler);
   };
 
   // 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",
+      apiUrl: "https://api.openstreetmap.org",
+      client_id: "0tmNTmd0Jo1dQp4AUmMBLtGiD9YpMuXzHefitcuVStc"
+    },
+    dev: {
+      url: "https://api06.dev.openstreetmap.org",
+      client_id: "Ee1wWJ6UlpERbF6BfTNOpwn0R8k_06mvMXdDUkeHMgw"
+    }
+  };
+  var osmApiConnections = [];
+  if (false) {
+    osmApiConnections.push({
+      url: null,
+      apiUrl: null,
+      client_id: 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/";
+  var showDonationMessage = true;
+
   // package.json
   var package_default = {
     name: "iD",
-    version: "2.22.0",
+    version: "2.30.4",
     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: "run-p dist:**",
       "dist:mapillary": "shx mkdir -p dist/mapillary-js && shx cp -R node_modules/mapillary-js/dist/* dist/mapillary-js/",
-      "dist:pannellum": "shx mkdir -p dist/pannellum-streetside && shx cp -R node_modules/pannellum/build/* dist/pannellum-streetside/",
+      "dist:pannellum": "shx mkdir -p dist/pannellum && shx cp -R node_modules/pannellum/build/* dist/pannellum/",
       "dist:min": "node config/esbuild.config.min.mjs",
       "dist:svg:iD": 'svg-sprite --symbol --symbol-dest . --shape-id-generator "iD-%s" --symbol-sprite dist/img/iD-sprite.svg "svg/iD-sprite/**/*.svg"',
       "dist:svg:community": 'svg-sprite --symbol --symbol-dest . --shape-id-generator "community-%s" --symbol-sprite dist/img/community-sprite.svg node_modules/osm-community-index/dist/img/*.svg',
       "dist:svg:fa": "svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/fa-sprite.svg svg/fontawesome/*.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:mapillary:signs": "svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/mapillary-sprite.svg node_modules/@rapideditor/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/@rapideditor/mapillary_sprite_source/package_objects/*.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",
       "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",
       "@mapbox/geojson-area": "^0.2.2",
       "@mapbox/sexagesimal": "1.2.0",
-      "@mapbox/vector-tile": "^1.3.1",
-      "@tmcw/togeojson": "^5.2.1",
-      "@turf/bbox-clip": "^6.0.0",
-      "abortcontroller-polyfill": "^1.4.0",
+      "@mapbox/vector-tile": "^2.0.3",
+      "@rapideditor/country-coder": "~5.3.0",
+      "@rapideditor/location-conflation": "~1.4.0",
+      "@tmcw/togeojson": "^5.8.1",
+      "@turf/bbox": "^7.1.0",
+      "@turf/bbox-clip": "^7.1.0",
+      "abortcontroller-polyfill": "^1.7.5",
       "aes-js": "^3.1.2",
-      "alif-toolkit": "^1.2.9",
-      "core-js-bundle": "^3.19.0",
+      "alif-toolkit": "^1.3.0",
+      "core-js-bundle": "^3.38.0",
       diacritics: "1.3.0",
+      exifr: "^7.1.3",
       "fast-deep-equal": "~3.1.1",
       "fast-json-stable-stringify": "2.1.0",
       "lodash-es": "~4.17.15",
-      marked: "~4.1.0",
+      marked: "~14.0.0",
       "node-diff3": "~3.1.0",
-      "osm-auth": "~2.0.0",
+      "osm-auth": "~2.5.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"
+      pbf: "^4.0.1",
+      "polygon-clipping": "~0.15.7",
+      rbush: "4.0.0",
+      "whatwg-fetch": "^3.6.20",
+      "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.6.0",
+      "@fortawesome/free-brands-svg-icons": "~6.6.0",
+      "@fortawesome/free-regular-svg-icons": "~6.6.0",
+      "@fortawesome/free-solid-svg-icons": "~6.6.0",
+      "@mapbox/maki": "^8.0.1",
+      "@openstreetmap/id-tagging-schema": "^6.8.1",
+      "@rapideditor/mapillary_sprite_source": "^1.8.0",
+      "@rapideditor/temaki": "^5.9.0",
+      "@transifex/api": "^7.1.2",
+      autoprefixer: "^10.4.20",
+      browserslist: "^4.23.3",
+      "browserslist-to-esbuild": "^2.1.1",
+      chai: "^4.5.0",
       chalk: "^4.1.2",
-      "cldr-core": "^41.0.0",
-      "cldr-localenames-full": "^41.0.0",
+      "cldr-core": "^45.0.0",
+      "cldr-localenames-full": "^45.0.0",
       "concat-files": "^0.1.1",
-      d3: "~7.6.1",
+      d3: "~7.9.0",
+      dotenv: "^16.4.5",
       "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.23.1",
+      "esbuild-visualizer": "^0.6.0",
+      eslint: "^9.9.0",
       "fetch-mock": "^9.11.0",
       gaze: "^1.1.3",
-      glob: "^8.0.3",
+      glob: "^10.4.5",
       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.4",
+      "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",
+      "mapillary-js": "4.1.2",
+      minimist: "^1.2.8",
+      mocha: "^10.7.3",
       "name-suggestion-index": "~6.0",
-      "node-fetch": "^2.6.1",
       "npm-run-all": "^4.0.0",
-      "osm-community-index": "~5.2.0",
-      postcss: "^8.1.1",
+      "osm-community-index": "~5.8.0",
+      postcss: "^8.4.41",
       "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.4",
       vparse: "~1.1.0"
     },
     engines: {
-      node: ">=16.14"
+      node: ">=18"
     },
     browserslist: [
-      "> 0.2%, last 6 major versions, Firefox ESR, maintained node versions"
+      "> 0.3%, last 6 major versions, not dead, Firefox ESR, maintained node versions"
     ]
   };
 
   var _mainFileFetcher = coreFileFetcher();
   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 v2 = (0, import_vparse.default)(ociVersion);
+    const ociVersionMinor = "".concat(v2.major, ".").concat(v2.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;
       const file = _fileMap[which];
       const url = file && _this.asset(file);
       if (!url) {
-        return Promise.reject(`Unknown data file for "${which}"`);
+        return Promise.reject('Unknown data file for "'.concat(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, which);
       }
+    };
+    function getUrl(url, which) {
       let prom = _inflight4[url];
       if (!prom) {
         _inflight4[url] = prom = fetch(url).then((response) => {
           if (!response.ok || !response.json) {
             throw new Error(response.status + " " + response.statusText);
           }
-          if (response.status === 204 || response.status === 205)
-            return;
+          if (response.status === 204 || response.status === 205) return;
           return response.json();
         }).then((result) => {
           delete _inflight4[url];
           if (!result) {
-            throw new Error(`No data loaded for "${which}"`);
+            throw new Error('No data loaded for "'.concat(which, '"'));
           }
           _cachedData[which] = result;
           return result;
         });
       }
       return prom;
-    };
+    }
     _this.fileMap = function(val) {
-      if (!arguments.length)
-        return _fileMap;
+      if (!arguments.length) return _fileMap;
       _fileMap = val;
       return _this;
     };
     let _assetPath = "";
     _this.assetPath = function(val) {
-      if (!arguments.length)
-        return _assetPath;
+      if (!arguments.length) return _assetPath;
       _assetPath = val;
       return _this;
     };
     let _assetMap = {};
     _this.assetMap = function(val) {
-      if (!arguments.length)
-        return _assetMap;
+      if (!arguments.length) return _assetMap;
       _assetMap = val;
       return _this;
     };
     _this.asset = (val) => {
-      if (/^http(s)?:\/\//i.test(val))
-        return val;
+      if (/^http(s)?:\/\//i.test(val)) return val;
       const filename = _assetPath + val;
       return _assetMap[filename] || filename;
     };
     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: { wikidata: "Q7835", nameEn: "Crimea", country: "RU", groups: ["151", "150", "UN"], level: "subterritory", callingCodes: ["7"] }, geometry: { type: "MultiPolygon", coordinates: [[[[33.5, 44], [36.4883, 45.0488], [36.475, 45.2411], [36.5049, 45.3136], [36.6545, 45.3417], [36.6645, 45.4514], [35.0498, 45.7683], [34.9601, 45.7563], [34.7991, 45.8101], [34.8015, 45.9005], [34.7548, 45.907], [34.6668, 45.9714], [34.6086, 45.9935], [34.5589, 45.9935], [34.5201, 45.951], [34.4873, 45.9427], [34.4415, 45.9599], [34.4122, 46.0025], [34.3391, 46.0611], [34.2511, 46.0532], [34.181, 46.068], [34.1293, 46.1049], [34.0731, 46.1177], [34.0527, 46.1084], [33.9155, 46.1594], [33.8523, 46.1986], [33.7972, 46.2048], [33.7405, 46.1855], [33.646, 46.2303], [33.6152, 46.2261], [33.6385, 46.1415], [33.6147, 46.1356], [33.5732, 46.1032], [33.5909, 46.0601], [33.5597, 46.0307], [31.5, 45.5], [33.5, 44]]]] } },
     { type: "Feature", properties: { wikidata: "Q12837", nameEn: "Iberia", level: "sharedLandform" }, geometry: null },
     { type: "Feature", properties: { wikidata: "Q14056", nameEn: "Jan Mayen", aliases: ["NO-22"], country: "NO", groups: ["SJ", "154", "150", "UN"], level: "subterritory" }, geometry: { type: "MultiPolygon", coordinates: [[[[-9.18243, 72.23144], [-10.71459, 70.09565], [-5.93364, 70.76368], [-9.18243, 72.23144]]]] } },
-    { type: "Feature", properties: { wikidata: "Q19188", nameEn: "Mainland China", country: "CN", groups: ["030", "142", "UN"], callingCodes: ["86"] }, geometry: { type: "MultiPolygon", coordinates: [[[[125.6131, 53.07229], [125.17522, 53.20225], [124.46078, 53.21881], [123.86158, 53.49391], [123.26989, 53.54843], [122.85966, 53.47395], [122.35063, 53.49565], [121.39213, 53.31888], [120.85633, 53.28499], [120.0451, 52.7359], [120.04049, 52.58773], [120.46454, 52.63811], [120.71673, 52.54099], [120.61346, 52.32447], [120.77337, 52.20805], [120.65907, 51.93544], [120.10963, 51.671], [119.13553, 50.37412], [119.38598, 50.35162], [119.27996, 50.13348], [119.11003, 50.00276], [118.61623, 49.93809], [117.82343, 49.52696], [117.48208, 49.62324], [117.27597, 49.62544], [116.71193, 49.83813], [116.03781, 48.87014], [116.06565, 48.81716], [115.78876, 48.51781], [115.811, 48.25699], [115.52082, 48.15367], [115.57128, 47.91988], [115.94296, 47.67741], [116.21879, 47.88505], [116.4465, 47.83662], [116.67405, 47.89039], [116.9723, 47.87285], [117.37875, 47.63627], [117.50181, 47.77216], [117.80196, 48.01661], [118.03676, 48.00982], [118.11009, 48.04], [118.22677, 48.03853], [118.29654, 48.00246], [118.55766, 47.99277], [118.7564, 47.76947], [119.12343, 47.66458], [119.13995, 47.53997], [119.35892, 47.48104], [119.31964, 47.42617], [119.54918, 47.29505], [119.56019, 47.24874], [119.62403, 47.24575], [119.71209, 47.19192], [119.85518, 46.92196], [119.91242, 46.90091], [119.89261, 46.66423], [119.80455, 46.67631], [119.77373, 46.62947], [119.68127, 46.59015], [119.65265, 46.62342], [119.42827, 46.63783], [119.32827, 46.61433], [119.24978, 46.64761], [119.10448, 46.65516], [119.00541, 46.74273], [118.92616, 46.72765], [118.89974, 46.77139], [118.8337, 46.77742], [118.78747, 46.68689], [118.30534, 46.73519], [117.69554, 46.50991], [117.60748, 46.59771], [117.41782, 46.57862], [117.36609, 46.36335], [116.83166, 46.38637], [116.75551, 46.33083], [116.58612, 46.30211], [116.26678, 45.96479], [116.24012, 45.8778], [116.27366, 45.78637], [116.16989, 45.68603], [115.60329, 45.44717], [114.94546, 45.37377], [114.74612, 45.43585], [114.54801, 45.38337], [114.5166, 45.27189], [113.70918, 44.72891], [112.74662, 44.86297], [112.4164, 45.06858], [111.98695, 45.09074], [111.76275, 44.98032], [111.40498, 44.3461], [111.96289, 43.81596], [111.93776, 43.68709], [111.79758, 43.6637], [111.59087, 43.51207], [111.0149, 43.3289], [110.4327, 42.78293], [110.08401, 42.6411], [109.89402, 42.63111], [109.452, 42.44842], [109.00679, 42.45302], [108.84489, 42.40246], [107.57258, 42.40898], [107.49681, 42.46221], [107.29755, 42.41395], [107.24774, 42.36107], [106.76517, 42.28741], [105.0123, 41.63188], [104.51667, 41.66113], [104.52258, 41.8706], [103.92804, 41.78246], [102.72403, 42.14675], [102.07645, 42.22519], [101.80515, 42.50074], [100.84979, 42.67087], [100.33297, 42.68231], [99.50671, 42.56535], [97.1777, 42.7964], [96.37926, 42.72055], [96.35658, 42.90363], [95.89543, 43.2528], [95.52594, 43.99353], [95.32891, 44.02407], [95.39772, 44.2805], [95.01191, 44.25274], [94.71959, 44.35284], [94.10003, 44.71016], [93.51161, 44.95964], [91.64048, 45.07408], [90.89169, 45.19667], [90.65114, 45.49314], [90.70907, 45.73437], [91.03026, 46.04194], [90.99672, 46.14207], [90.89639, 46.30711], [91.07696, 46.57315], [91.0147, 46.58171], [91.03649, 46.72916], [90.84035, 46.99525], [90.76108, 46.99399], [90.48542, 47.30438], [90.48854, 47.41826], [90.33598, 47.68303], [90.10871, 47.7375], [90.06512, 47.88177], [89.76624, 47.82745], [89.55453, 48.0423], [89.0711, 47.98528], [88.93186, 48.10263], [88.8011, 48.11302], [88.58316, 48.21893], [88.58939, 48.34531], [87.96361, 48.58478], [88.0788, 48.71436], [87.73822, 48.89582], [87.88171, 48.95853], [87.81333, 49.17354], [87.48983, 49.13794], [87.478, 49.07403], [87.28386, 49.11626], [86.87238, 49.12432], [86.73568, 48.99918], [86.75343, 48.70331], [86.38069, 48.46064], [85.73581, 48.3939], [85.5169, 48.05493], [85.61067, 47.49753], [85.69696, 47.2898], [85.54294, 47.06171], [85.22443, 47.04816], [84.93995, 46.87399], [84.73077, 47.01394], [83.92184, 46.98912], [83.04622, 47.19053], [82.21792, 45.56619], [82.58474, 45.40027], [82.51374, 45.1755], [81.73278, 45.3504], [80.11169, 45.03352], [79.8987, 44.89957], [80.38384, 44.63073], [80.40229, 44.23319], [80.40031, 44.10986], [80.75156, 43.44948], [80.69718, 43.32589], [80.77771, 43.30065], [80.78817, 43.14235], [80.62913, 43.141], [80.3735, 43.01557], [80.58999, 42.9011], [80.38169, 42.83142], [80.26886, 42.8366], [80.16892, 42.61137], [80.26841, 42.23797], [80.17807, 42.21166], [80.17842, 42.03211], [79.92977, 42.04113], [78.3732, 41.39603], [78.15757, 41.38565], [78.12873, 41.23091], [77.81287, 41.14307], [77.76206, 41.01574], [77.52723, 41.00227], [77.3693, 41.0375], [77.28004, 41.0033], [76.99302, 41.0696], [76.75681, 40.95354], [76.5261, 40.46114], [76.33659, 40.3482], [75.96168, 40.38064], [75.91361, 40.2948], [75.69663, 40.28642], [75.5854, 40.66874], [75.22834, 40.45382], [75.08243, 40.43945], [74.82013, 40.52197], [74.78168, 40.44886], [74.85996, 40.32857], [74.69875, 40.34668], [74.35063, 40.09742], [74.25533, 40.13191], [73.97049, 40.04378], [73.83006, 39.76136], [73.9051, 39.75073], [73.92354, 39.69565], [73.94683, 39.60733], [73.87018, 39.47879], [73.59831, 39.46425], [73.59241, 39.40843], [73.5004, 39.38402], [73.55396, 39.3543], [73.54572, 39.27567], [73.60638, 39.24534], [73.75823, 39.023], [73.81728, 39.04007], [73.82964, 38.91517], [73.7445, 38.93867], [73.7033, 38.84782], [73.80656, 38.66449], [73.79806, 38.61106], [73.97933, 38.52945], [74.17022, 38.65504], [74.51217, 38.47034], [74.69619, 38.42947], [74.69894, 38.22155], [74.80331, 38.19889], [74.82665, 38.07359], [74.9063, 38.03033], [74.92416, 37.83428], [75.00935, 37.77486], [74.8912, 37.67576], [74.94338, 37.55501], [75.06011, 37.52779], [75.15899, 37.41443], [75.09719, 37.37297], [75.12328, 37.31839], [74.88887, 37.23275], [74.80605, 37.21565], [74.49981, 37.24518], [74.56453, 37.03023], [75.13839, 37.02622], [75.40481, 36.95382], [75.45562, 36.71971], [75.72737, 36.7529], [75.92391, 36.56986], [76.0324, 36.41198], [76.00906, 36.17511], [75.93028, 36.13136], [76.15325, 35.9264], [76.14913, 35.82848], [76.33453, 35.84296], [76.50961, 35.8908], [76.77323, 35.66062], [76.84539, 35.67356], [76.96624, 35.5932], [77.44277, 35.46132], [77.70232, 35.46244], [77.80532, 35.52058], [78.11664, 35.48022], [78.03466, 35.3785], [78.00033, 35.23954], [78.22692, 34.88771], [78.18435, 34.7998], [78.27781, 34.61484], [78.54964, 34.57283], [78.56475, 34.50835], [78.74465, 34.45174], [79.05364, 34.32482], [78.99802, 34.3027], [78.91769, 34.15452], [78.66225, 34.08858], [78.65657, 34.03195], [78.73367, 34.01121], [78.77349, 33.73871], [78.67599, 33.66445], [78.73636, 33.56521], [79.15252, 33.17156], [79.14016, 33.02545], [79.46562, 32.69668], [79.26768, 32.53277], [79.13174, 32.47766], [79.0979, 32.38051], [78.99322, 32.37948], [78.96713, 32.33655], [78.7831, 32.46873], [78.73916, 32.69438], [78.38897, 32.53938], [78.4645, 32.45367], [78.49609, 32.2762], [78.68754, 32.10256], [78.74404, 32.00384], [78.78036, 31.99478], [78.69933, 31.78723], [78.84516, 31.60631], [78.71032, 31.50197], [78.77898, 31.31209], [78.89344, 31.30481], [79.01931, 31.42817], [79.14016, 31.43403], [79.30694, 31.17357], [79.59884, 30.93943], [79.93255, 30.88288], [80.20721, 30.58541], [80.54504, 30.44936], [80.83343, 30.32023], [81.03953, 30.20059], [81.12842, 30.01395], [81.24362, 30.0126], [81.29032, 30.08806], [81.2623, 30.14596], [81.33355, 30.15303], [81.39928, 30.21862], [81.41018, 30.42153], [81.5459, 30.37688], [81.62033, 30.44703], [81.99082, 30.33423], [82.10135, 30.35439], [82.10757, 30.23745], [82.19475, 30.16884], [82.16984, 30.0692], [82.38622, 30.02608], [82.5341, 29.9735], [82.73024, 29.81695], [83.07116, 29.61957], [83.28131, 29.56813], [83.44787, 29.30513], [83.63156, 29.16249], [83.82303, 29.30513], [83.97559, 29.33091], [84.18107, 29.23451], [84.24801, 29.02783], [84.2231, 28.89571], [84.47528, 28.74023], [84.62317, 28.73887], [84.85511, 28.58041], [85.06059, 28.68562], [85.19135, 28.62825], [85.18668, 28.54076], [85.10729, 28.34092], [85.38127, 28.28336], [85.4233, 28.32996], [85.59765, 28.30529], [85.60854, 28.25045], [85.69105, 28.38475], [85.71907, 28.38064], [85.74864, 28.23126], [85.84672, 28.18187], [85.90743, 28.05144], [85.97813, 27.99023], [85.94946, 27.9401], [86.06309, 27.90021], [86.12069, 27.93047], [86.08333, 28.02121], [86.088, 28.09264], [86.18607, 28.17364], [86.22966, 27.9786], [86.42736, 27.91122], [86.51609, 27.96623], [86.56265, 28.09569], [86.74181, 28.10638], [86.75582, 28.04182], [87.03757, 27.94835], [87.11696, 27.84104], [87.56996, 27.84517], [87.72718, 27.80938], [87.82681, 27.95248], [88.13378, 27.88015], [88.1278, 27.95417], [88.25332, 27.9478], [88.54858, 28.06057], [88.63235, 28.12356], [88.83559, 28.01936], [88.88091, 27.85192], [88.77517, 27.45415], [88.82981, 27.38814], [88.91901, 27.32483], [88.93678, 27.33777], [88.96947, 27.30319], [89.00216, 27.32532], [88.95355, 27.4106], [88.97213, 27.51671], [89.0582, 27.60985], [89.12825, 27.62502], [89.59525, 28.16433], [89.79762, 28.23979], [90.13387, 28.19178], [90.58842, 28.02838], [90.69894, 28.07784], [91.20019, 27.98715], [91.25779, 28.07509], [91.46327, 28.0064], [91.48973, 27.93903], [91.5629, 27.84823], [91.6469, 27.76358], [91.84722, 27.76325], [91.87057, 27.7195], [92.27432, 27.89077], [92.32101, 27.79363], [92.42538, 27.80092], [92.7275, 27.98662], [92.73025, 28.05814], [92.65472, 28.07632], [92.67486, 28.15018], [92.93075, 28.25671], [93.14635, 28.37035], [93.18069, 28.50319], [93.44621, 28.67189], [93.72797, 28.68821], [94.35897, 29.01965], [94.2752, 29.11687], [94.69318, 29.31739], [94.81353, 29.17804], [95.0978, 29.14446], [95.11291, 29.09527], [95.2214, 29.10727], [95.26122, 29.07727], [95.3038, 29.13847], [95.41091, 29.13007], [95.50842, 29.13487], [95.72086, 29.20797], [95.75149, 29.32063], [95.84899, 29.31464], [96.05361, 29.38167], [96.31316, 29.18643], [96.18682, 29.11087], [96.20467, 29.02325], [96.3626, 29.10607], [96.61391, 28.72742], [96.40929, 28.51526], [96.48895, 28.42955], [96.6455, 28.61657], [96.85561, 28.4875], [96.88445, 28.39452], [96.98882, 28.32564], [97.1289, 28.3619], [97.34547, 28.21385], [97.41729, 28.29783], [97.47085, 28.2688], [97.50518, 28.49716], [97.56835, 28.55628], [97.70705, 28.5056], [97.79632, 28.33168], [97.90069, 28.3776], [98.15337, 28.12114], [98.13964, 27.9478], [98.32641, 27.51385], [98.42529, 27.55404], [98.43353, 27.67086], [98.69582, 27.56499], [98.7333, 26.85615], [98.77547, 26.61994], [98.72741, 26.36183], [98.67797, 26.24487], [98.7329, 26.17218], [98.66884, 26.09165], [98.63128, 26.15492], [98.57085, 26.11547], [98.60763, 26.01512], [98.70818, 25.86241], [98.63128, 25.79937], [98.54064, 25.85129], [98.40606, 25.61129], [98.31268, 25.55307], [98.25774, 25.6051], [98.16848, 25.62739], [98.18084, 25.56298], [98.12591, 25.50722], [98.14925, 25.41547], [97.92541, 25.20815], [97.83614, 25.2715], [97.77023, 25.11492], [97.72216, 25.08508], [97.72903, 24.91332], [97.79949, 24.85655], [97.76481, 24.8289], [97.73127, 24.83015], [97.70181, 24.84557], [97.64354, 24.79171], [97.56648, 24.76475], [97.56383, 24.75535], [97.5542, 24.74943], [97.54675, 24.74202], [97.56525, 24.72838], [97.56286, 24.54535], [97.52757, 24.43748], [97.60029, 24.4401], [97.66998, 24.45288], [97.7098, 24.35658], [97.65624, 24.33781], [97.66723, 24.30027], [97.71941, 24.29652], [97.76799, 24.26365], [97.72998, 24.2302], [97.72799, 24.18883], [97.75305, 24.16902], [97.72903, 24.12606], [97.62363, 24.00506], [97.5247, 23.94032], [97.64667, 23.84574], [97.72302, 23.89288], [97.79456, 23.94836], [97.79416, 23.95663], [97.84328, 23.97603], [97.86545, 23.97723], [97.88811, 23.97446], [97.8955, 23.97758], [97.89676, 23.97931], [97.89683, 23.98389], [97.88814, 23.98605], [97.88414, 23.99405], [97.88616, 24.00463], [97.90998, 24.02094], [97.93951, 24.01953], [97.98691, 24.03897], [97.99583, 24.04932], [98.04709, 24.07616], [98.05302, 24.07408], [98.05671, 24.07961], [98.0607, 24.07812], [98.06703, 24.08028], [98.07806, 24.07988], [98.20666, 24.11406], [98.54476, 24.13119], [98.59256, 24.08371], [98.85319, 24.13042], [98.87998, 24.15624], [98.89632, 24.10612], [98.67797, 23.9644], [98.68209, 23.80492], [98.79607, 23.77947], [98.82933, 23.72921], [98.81775, 23.694], [98.88396, 23.59555], [98.80294, 23.5345], [98.82877, 23.47908], [98.87683, 23.48995], [98.92104, 23.36946], [98.87573, 23.33038], [98.93958, 23.31414], [98.92515, 23.29535], [98.88597, 23.18656], [99.05975, 23.16382], [99.04601, 23.12215], [99.25741, 23.09025], [99.34127, 23.13099], [99.52214, 23.08218], [99.54218, 22.90014], [99.43537, 22.94086], [99.45654, 22.85726], [99.31243, 22.73893], [99.38247, 22.57544], [99.37972, 22.50188], [99.28771, 22.4105], [99.17318, 22.18025], [99.19176, 22.16983], [99.1552, 22.15874], [99.33166, 22.09656], [99.47585, 22.13345], [99.85351, 22.04183], [99.96612, 22.05965], [99.99084, 21.97053], [99.94003, 21.82782], [99.98654, 21.71064], [100.04956, 21.66843], [100.12679, 21.70539], [100.17486, 21.65306], [100.10757, 21.59945], [100.12542, 21.50365], [100.1625, 21.48704], [100.18447, 21.51898], [100.25863, 21.47043], [100.35201, 21.53176], [100.42892, 21.54325], [100.4811, 21.46148], [100.57861, 21.45637], [100.72143, 21.51898], [100.87265, 21.67396], [101.11744, 21.77659], [101.15156, 21.56129], [101.2124, 21.56422], [101.19349, 21.41959], [101.26912, 21.36482], [101.2229, 21.23271], [101.29326, 21.17254], [101.54563, 21.25668], [101.6068, 21.23329], [101.59491, 21.18621], [101.60886, 21.17947], [101.66977, 21.20004], [101.70548, 21.14911], [101.7622, 21.14813], [101.79266, 21.19025], [101.76745, 21.21571], [101.83887, 21.20983], [101.84412, 21.25291], [101.74014, 21.30967], [101.74224, 21.48276], [101.7727, 21.51794], [101.7475, 21.5873], [101.80001, 21.57461], [101.83257, 21.61562], [101.74555, 21.72852], [101.7791, 21.83019], [101.62566, 21.96574], [101.57525, 22.13026], [101.60675, 22.13513], [101.53638, 22.24794], [101.56789, 22.28876], [101.61306, 22.27515], [101.68973, 22.46843], [101.7685, 22.50337], [101.86828, 22.38397], [101.90714, 22.38688], [101.91344, 22.44417], [101.98487, 22.42766], [102.03633, 22.46164], [102.1245, 22.43372], [102.14099, 22.40092], [102.16621, 22.43336], [102.26428, 22.41321], [102.25339, 22.4607], [102.41061, 22.64184], [102.38415, 22.67919], [102.42618, 22.69212], [102.46665, 22.77108], [102.51802, 22.77969], [102.57095, 22.7036], [102.60675, 22.73376], [102.8636, 22.60735], [102.9321, 22.48659], [103.0722, 22.44775], [103.07843, 22.50097], [103.17961, 22.55705], [103.15782, 22.59873], [103.18895, 22.64471], [103.28079, 22.68063], [103.32282, 22.8127], [103.43179, 22.75816], [103.43646, 22.70648], [103.52675, 22.59155], [103.57812, 22.65764], [103.56255, 22.69499], [103.64506, 22.79979], [103.87904, 22.56683], [103.93286, 22.52703], [103.94513, 22.52553], [103.95191, 22.5134], [103.96352, 22.50584], [103.96783, 22.51173], [103.97384, 22.50634], [103.99247, 22.51958], [104.01088, 22.51823], [104.03734, 22.72945], [104.11384, 22.80363], [104.27084, 22.8457], [104.25683, 22.76534], [104.35593, 22.69353], [104.47225, 22.75813], [104.58122, 22.85571], [104.60457, 22.81841], [104.65283, 22.83419], [104.72755, 22.81984], [104.77114, 22.90017], [104.84942, 22.93631], [104.86765, 22.95178], [104.8334, 23.01484], [104.79478, 23.12934], [104.87382, 23.12854], [104.87992, 23.17141], [104.91435, 23.18666], [104.9486, 23.17235], [104.96532, 23.20463], [104.98712, 23.19176], [105.07002, 23.26248], [105.11672, 23.25247], [105.17276, 23.28679], [105.22569, 23.27249], [105.32376, 23.39684], [105.40782, 23.28107], [105.42805, 23.30824], [105.49966, 23.20669], [105.56037, 23.16806], [105.57594, 23.075], [105.72382, 23.06641], [105.8726, 22.92756], [105.90119, 22.94168], [105.99568, 22.94178], [106.00179, 22.99049], [106.19705, 22.98475], [106.27022, 22.87722], [106.34961, 22.86718], [106.49749, 22.91164], [106.51306, 22.94891], [106.55976, 22.92311], [106.60179, 22.92884], [106.6516, 22.86862], [106.6734, 22.89587], [106.71387, 22.88296], [106.71128, 22.85982], [106.78422, 22.81532], [106.81271, 22.8226], [106.83685, 22.8098], [106.82404, 22.7881], [106.76293, 22.73491], [106.72321, 22.63606], [106.71698, 22.58432], [106.65316, 22.5757], [106.61269, 22.60301], [106.58395, 22.474], [106.55665, 22.46498], [106.57221, 22.37], [106.55976, 22.34841], [106.6516, 22.33977], [106.69986, 22.22309], [106.67495, 22.1885], [106.6983, 22.15102], [106.70142, 22.02409], [106.68274, 21.99811], [106.69276, 21.96013], [106.72551, 21.97923], [106.74345, 22.00965], [106.81038, 21.97934], [106.9178, 21.97357], [106.92714, 21.93459], [106.97228, 21.92592], [106.99252, 21.95191], [107.05634, 21.92303], [107.06101, 21.88982], [107.00964, 21.85948], [107.02615, 21.81981], [107.10771, 21.79879], [107.20734, 21.71493], [107.24625, 21.7077], [107.29296, 21.74674], [107.35834, 21.6672], [107.35989, 21.60063], [107.38636, 21.59774], [107.41593, 21.64839], [107.47197, 21.6672], [107.49532, 21.62958], [107.49065, 21.59774], [107.54047, 21.5934], [107.56537, 21.61945], [107.66967, 21.60787], [107.80355, 21.66141], [107.86114, 21.65128], [107.90006, 21.5905], [107.92652, 21.58906], [107.95232, 21.5388], [107.96774, 21.53601], [107.97074, 21.54072], [107.97383, 21.53961], [107.97932, 21.54503], [108.02926, 21.54997], [108.0569, 21.53604], [108.10003, 21.47338], [108.00365, 17.98159], [111.60491, 13.57105], [118.41371, 24.06775], [118.11703, 24.39734], [118.28244, 24.51231], [118.35291, 24.51645], [118.42453, 24.54644], [118.56434, 24.49266], [120.49232, 25.22863], [121.03532, 26.8787], [123.5458, 31.01942], [122.29378, 31.76513], [122.80525, 33.30571], [123.85601, 37.49093], [123.90497, 38.79949], [124.17532, 39.8232], [124.23201, 39.9248], [124.35029, 39.95639], [124.37089, 40.03004], [124.3322, 40.05573], [124.38556, 40.11047], [124.40719, 40.13655], [124.86913, 40.45387], [125.71172, 40.85223], [125.76869, 40.87908], [126.00335, 40.92835], [126.242, 41.15454], [126.53189, 41.35206], [126.60631, 41.65565], [126.90729, 41.79955], [127.17841, 41.59714], [127.29712, 41.49473], [127.92943, 41.44291], [128.02633, 41.42103], [128.03311, 41.39232], [128.12967, 41.37931], [128.18546, 41.41279], [128.20061, 41.40895], [128.30716, 41.60322], [128.15119, 41.74568], [128.04487, 42.01769], [128.94007, 42.03537], [128.96068, 42.06657], [129.15178, 42.17224], [129.22285, 42.26491], [129.22423, 42.3553], [129.28541, 42.41574], [129.42882, 42.44702], [129.54701, 42.37254], [129.60482, 42.44461], [129.72541, 42.43739], [129.75294, 42.59409], [129.77183, 42.69435], [129.7835, 42.76521], [129.80719, 42.79218], [129.83277, 42.86746], [129.85261, 42.96494], [129.8865, 43.00395], [129.95082, 43.01051], [129.96409, 42.97306], [130.12957, 42.98361], [130.09764, 42.91425], [130.26095, 42.9027], [130.23068, 42.80125], [130.2385, 42.71127], [130.41826, 42.6011], [130.44361, 42.54849], [130.50123, 42.61636], [130.55143, 42.52158], [130.62107, 42.58413], [130.56576, 42.68925], [130.40213, 42.70788], [130.44361, 42.76205], [130.66524, 42.84753], [131.02438, 42.86518], [131.02668, 42.91246], [131.135, 42.94114], [131.10274, 43.04734], [131.20414, 43.13654], [131.19031, 43.21385], [131.30324, 43.39498], [131.29402, 43.46695], [131.19492, 43.53047], [131.21105, 43.82383], [131.26176, 43.94011], [131.23583, 43.96085], [131.25484, 44.03131], [131.30365, 44.04262], [131.1108, 44.70266], [130.95639, 44.85154], [131.48415, 44.99513], [131.68466, 45.12374], [131.66852, 45.2196], [131.76532, 45.22609], [131.86903, 45.33636], [131.99417, 45.2567], [132.83978, 45.05916], [132.96373, 45.0212], [133.12293, 45.1332], [133.09279, 45.25693], [133.19419, 45.51913], [133.41083, 45.57723], [133.48457, 45.86203], [133.60442, 45.90053], [133.67569, 45.9759], [133.72695, 46.05576], [133.68047, 46.14697], [133.88097, 46.25066], [133.91496, 46.4274], [133.84104, 46.46681], [134.03538, 46.75668], [134.20016, 47.33458], [134.50898, 47.4812], [134.7671, 47.72051], [134.55508, 47.98651], [134.67098, 48.1564], [134.75328, 48.36763], [134.49516, 48.42884], [132.66989, 47.96491], [132.57309, 47.71741], [131.90448, 47.68011], [131.2635, 47.73325], [131.09871, 47.6852], [130.95985, 47.6957], [130.90915, 47.90623], [130.65103, 48.10052], [130.84462, 48.30942], [130.52147, 48.61745], [130.66946, 48.88251], [130.43232, 48.90844], [130.2355, 48.86741], [129.85416, 49.11067], [129.67598, 49.29596], [129.50685, 49.42398], [129.40398, 49.44194], [129.35317, 49.3481], [129.23232, 49.40353], [129.11153, 49.36813], [128.72896, 49.58676], [127.83476, 49.5748], [127.53516, 49.84306], [127.49299, 50.01251], [127.60515, 50.23503], [127.37384, 50.28393], [127.36009, 50.43787], [127.28765, 50.46585], [127.36335, 50.58306], [127.28165, 50.72075], [127.14586, 50.91152], [126.93135, 51.0841], [126.90369, 51.3238], [126.68349, 51.70607], [126.44606, 51.98254], [126.558, 52.13738], [125.6131, 53.07229]], [[113.56865, 22.20973], [113.57123, 22.20416], [113.60504, 22.20464], [113.63011, 22.10782], [113.57191, 22.07696], [113.54839, 22.10909], [113.54942, 22.14519], [113.54093, 22.15497], [113.52659, 22.18271], [113.53552, 22.20607], [113.53301, 22.21235], [113.53591, 22.21369], [113.54093, 22.21314], [113.54333, 22.21688], [113.5508, 22.21672], [113.56865, 22.20973]], [[114.50148, 22.15017], [113.92195, 22.13873], [113.83338, 22.1826], [113.81621, 22.2163], [113.86771, 22.42972], [114.03113, 22.5065], [114.05438, 22.5026], [114.05729, 22.51104], [114.06272, 22.51617], [114.07267, 22.51855], [114.07817, 22.52997], [114.08606, 22.53276], [114.09048, 22.53716], [114.09692, 22.53435], [114.1034, 22.5352], [114.11181, 22.52878], [114.11656, 22.53415], [114.12665, 22.54003], [114.13823, 22.54319], [114.1482, 22.54091], [114.15123, 22.55163], [114.1597, 22.56041], [114.17247, 22.55944], [114.18338, 22.55444], [114.20655, 22.55706], [114.22185, 22.55343], [114.22888, 22.5436], [114.25154, 22.55977], [114.44998, 22.55977], [114.50148, 22.15017]]]] } },
+    { type: "Feature", properties: { wikidata: "Q19188", nameEn: "Mainland China", country: "CN", groups: ["030", "142", "UN"], callingCodes: ["86"] }, geometry: { type: "MultiPolygon", coordinates: [[[[125.6131, 53.07229], [125.17522, 53.20225], [124.46078, 53.21881], [123.86158, 53.49391], [123.26989, 53.54843], [122.85966, 53.47395], [122.35063, 53.49565], [121.39213, 53.31888], [120.85633, 53.28499], [120.0451, 52.7359], [120.04049, 52.58773], [120.46454, 52.63811], [120.71673, 52.54099], [120.61346, 52.32447], [120.77337, 52.20805], [120.65907, 51.93544], [120.10963, 51.671], [119.13553, 50.37412], [119.38598, 50.35162], [119.27996, 50.13348], [119.11003, 50.00276], [118.61623, 49.93809], [117.82343, 49.52696], [117.48208, 49.62324], [117.27597, 49.62544], [116.71193, 49.83813], [116.03781, 48.87014], [116.06565, 48.81716], [115.78876, 48.51781], [115.811, 48.25699], [115.52082, 48.15367], [115.57128, 47.91988], [115.94296, 47.67741], [116.21879, 47.88505], [116.4465, 47.83662], [116.67405, 47.89039], [116.9723, 47.87285], [117.37875, 47.63627], [117.50181, 47.77216], [117.80196, 48.01661], [118.03676, 48.00982], [118.11009, 48.04], [118.22677, 48.03853], [118.29654, 48.00246], [118.55766, 47.99277], [118.7564, 47.76947], [119.12343, 47.66458], [119.13995, 47.53997], [119.35892, 47.48104], [119.31964, 47.42617], [119.54918, 47.29505], [119.56019, 47.24874], [119.62403, 47.24575], [119.71209, 47.19192], [119.85518, 46.92196], [119.91242, 46.90091], [119.89261, 46.66423], [119.80455, 46.67631], [119.77373, 46.62947], [119.68127, 46.59015], [119.65265, 46.62342], [119.42827, 46.63783], [119.32827, 46.61433], [119.24978, 46.64761], [119.10448, 46.65516], [119.00541, 46.74273], [118.92616, 46.72765], [118.89974, 46.77139], [118.8337, 46.77742], [118.78747, 46.68689], [118.30534, 46.73519], [117.69554, 46.50991], [117.60748, 46.59771], [117.41782, 46.57862], [117.36609, 46.36335], [116.83166, 46.38637], [116.75551, 46.33083], [116.58612, 46.30211], [116.26678, 45.96479], [116.24012, 45.8778], [116.27366, 45.78637], [116.16989, 45.68603], [115.60329, 45.44717], [114.94546, 45.37377], [114.74612, 45.43585], [114.54801, 45.38337], [114.5166, 45.27189], [113.70918, 44.72891], [112.74662, 44.86297], [112.4164, 45.06858], [111.98695, 45.09074], [111.76275, 44.98032], [111.40498, 44.3461], [111.96289, 43.81596], [111.93776, 43.68709], [111.79758, 43.6637], [111.59087, 43.51207], [111.0149, 43.3289], [110.4327, 42.78293], [110.08401, 42.6411], [109.89402, 42.63111], [109.452, 42.44842], [109.00679, 42.45302], [108.84489, 42.40246], [107.57258, 42.40898], [107.49681, 42.46221], [107.29755, 42.41395], [107.24774, 42.36107], [106.76517, 42.28741], [105.0123, 41.63188], [104.51667, 41.66113], [104.52258, 41.8706], [103.92804, 41.78246], [102.72403, 42.14675], [102.07645, 42.22519], [101.80515, 42.50074], [100.84979, 42.67087], [100.33297, 42.68231], [99.50671, 42.56535], [97.1777, 42.7964], [96.37926, 42.72055], [96.35658, 42.90363], [95.89543, 43.2528], [95.52594, 43.99353], [95.32891, 44.02407], [95.39772, 44.2805], [95.01191, 44.25274], [94.71959, 44.35284], [94.10003, 44.71016], [93.51161, 44.95964], [91.64048, 45.07408], [90.89169, 45.19667], [90.65114, 45.49314], [90.70907, 45.73437], [91.03026, 46.04194], [90.99672, 46.14207], [90.89639, 46.30711], [91.07696, 46.57315], [91.0147, 46.58171], [91.03649, 46.72916], [90.84035, 46.99525], [90.76108, 46.99399], [90.48542, 47.30438], [90.48854, 47.41826], [90.33598, 47.68303], [90.10871, 47.7375], [90.06512, 47.88177], [89.76624, 47.82745], [89.55453, 48.0423], [89.0711, 47.98528], [88.93186, 48.10263], [88.8011, 48.11302], [88.58316, 48.21893], [88.58939, 48.34531], [87.96361, 48.58478], [88.0788, 48.71436], [87.73822, 48.89582], [87.88171, 48.95853], [87.81333, 49.17354], [87.48983, 49.13794], [87.478, 49.07403], [87.28386, 49.11626], [86.87238, 49.12432], [86.73568, 48.99918], [86.75343, 48.70331], [86.38069, 48.46064], [85.73581, 48.3939], [85.5169, 48.05493], [85.61067, 47.49753], [85.69696, 47.2898], [85.54294, 47.06171], [85.22443, 47.04816], [84.93995, 46.87399], [84.73077, 47.01394], [83.92184, 46.98912], [83.04622, 47.19053], [82.21792, 45.56619], [82.58474, 45.40027], [82.51374, 45.1755], [81.73278, 45.3504], [80.11169, 45.03352], [79.8987, 44.89957], [80.38384, 44.63073], [80.40229, 44.23319], [80.40031, 44.10986], [80.75156, 43.44948], [80.69718, 43.32589], [80.77771, 43.30065], [80.78817, 43.14235], [80.62913, 43.141], [80.3735, 43.01557], [80.58999, 42.9011], [80.38169, 42.83142], [80.26886, 42.8366], [80.16892, 42.61137], [80.26841, 42.23797], [80.17807, 42.21166], [80.17842, 42.03211], [79.92977, 42.04113], [78.3732, 41.39603], [78.15757, 41.38565], [78.12873, 41.23091], [77.81287, 41.14307], [77.76206, 41.01574], [77.52723, 41.00227], [77.3693, 41.0375], [77.28004, 41.0033], [76.99302, 41.0696], [76.75681, 40.95354], [76.5261, 40.46114], [76.33659, 40.3482], [75.96168, 40.38064], [75.91361, 40.2948], [75.69663, 40.28642], [75.5854, 40.66874], [75.22834, 40.45382], [75.08243, 40.43945], [74.82013, 40.52197], [74.78168, 40.44886], [74.85996, 40.32857], [74.69875, 40.34668], [74.35063, 40.09742], [74.25533, 40.13191], [73.97049, 40.04378], [73.83006, 39.76136], [73.9051, 39.75073], [73.92354, 39.69565], [73.94683, 39.60733], [73.87018, 39.47879], [73.59831, 39.46425], [73.59241, 39.40843], [73.5004, 39.38402], [73.55396, 39.3543], [73.54572, 39.27567], [73.60638, 39.24534], [73.75823, 39.023], [73.81728, 39.04007], [73.82964, 38.91517], [73.7445, 38.93867], [73.7033, 38.84782], [73.80656, 38.66449], [73.79806, 38.61106], [73.97933, 38.52945], [74.17022, 38.65504], [74.51217, 38.47034], [74.69619, 38.42947], [74.69894, 38.22155], [74.80331, 38.19889], [74.82665, 38.07359], [74.9063, 38.03033], [74.92416, 37.83428], [75.00935, 37.77486], [74.8912, 37.67576], [74.94338, 37.55501], [75.06011, 37.52779], [75.15899, 37.41443], [75.09719, 37.37297], [75.12328, 37.31839], [74.88887, 37.23275], [74.80605, 37.21565], [74.49981, 37.24518], [74.56453, 37.03023], [75.13839, 37.02622], [75.40481, 36.95382], [75.45562, 36.71971], [75.72737, 36.7529], [75.92391, 36.56986], [76.0324, 36.41198], [76.00906, 36.17511], [75.93028, 36.13136], [76.15325, 35.9264], [76.14913, 35.82848], [76.33453, 35.84296], [76.50961, 35.8908], [76.77323, 35.66062], [76.84539, 35.67356], [76.96624, 35.5932], [77.44277, 35.46132], [77.70232, 35.46244], [77.80532, 35.52058], [78.11664, 35.48022], [78.03466, 35.3785], [78.00033, 35.23954], [78.22692, 34.88771], [78.18435, 34.7998], [78.27781, 34.61484], [78.54964, 34.57283], [78.56475, 34.50835], [78.74465, 34.45174], [79.05364, 34.32482], [78.99802, 34.3027], [78.91769, 34.15452], [78.66225, 34.08858], [78.65657, 34.03195], [78.73367, 34.01121], [78.77349, 33.73871], [78.67599, 33.66445], [78.73636, 33.56521], [79.15252, 33.17156], [79.14016, 33.02545], [79.46562, 32.69668], [79.26768, 32.53277], [79.13174, 32.47766], [79.0979, 32.38051], [78.99322, 32.37948], [78.96713, 32.33655], [78.7831, 32.46873], [78.73916, 32.69438], [78.38897, 32.53938], [78.4645, 32.45367], [78.49609, 32.2762], [78.68754, 32.10256], [78.74404, 32.00384], [78.78036, 31.99478], [78.69933, 31.78723], [78.84516, 31.60631], [78.71032, 31.50197], [78.77898, 31.31209], [78.89344, 31.30481], [79.01931, 31.42817], [79.14016, 31.43403], [79.30694, 31.17357], [79.59884, 30.93943], [79.93255, 30.88288], [80.20721, 30.58541], [80.54504, 30.44936], [80.83343, 30.32023], [81.03953, 30.20059], [81.12842, 30.01395], [81.24362, 30.0126], [81.29032, 30.08806], [81.2623, 30.14596], [81.33355, 30.15303], [81.39928, 30.21862], [81.41018, 30.42153], [81.5459, 30.37688], [81.62033, 30.44703], [81.99082, 30.33423], [82.10135, 30.35439], [82.10757, 30.23745], [82.19475, 30.16884], [82.16984, 30.0692], [82.38622, 30.02608], [82.5341, 29.9735], [82.73024, 29.81695], [83.07116, 29.61957], [83.28131, 29.56813], [83.44787, 29.30513], [83.63156, 29.16249], [83.82303, 29.30513], [83.97559, 29.33091], [84.18107, 29.23451], [84.24801, 29.02783], [84.2231, 28.89571], [84.47528, 28.74023], [84.62317, 28.73887], [84.85511, 28.58041], [85.06059, 28.68562], [85.19135, 28.62825], [85.18668, 28.54076], [85.10729, 28.34092], [85.38127, 28.28336], [85.4233, 28.32996], [85.59765, 28.30529], [85.60854, 28.25045], [85.69105, 28.38475], [85.71907, 28.38064], [85.74864, 28.23126], [85.84672, 28.18187], [85.90743, 28.05144], [85.97813, 27.99023], [85.94946, 27.9401], [86.06309, 27.90021], [86.12069, 27.93047], [86.08333, 28.02121], [86.088, 28.09264], [86.18607, 28.17364], [86.22966, 27.9786], [86.42736, 27.91122], [86.51609, 27.96623], [86.56265, 28.09569], [86.74181, 28.10638], [86.75582, 28.04182], [87.03757, 27.94835], [87.11696, 27.84104], [87.56996, 27.84517], [87.72718, 27.80938], [87.82681, 27.95248], [88.13378, 27.88015], [88.1278, 27.95417], [88.25332, 27.9478], [88.54858, 28.06057], [88.63235, 28.12356], [88.83559, 28.01936], [88.88091, 27.85192], [88.77517, 27.45415], [88.82981, 27.38814], [88.91901, 27.32483], [88.93678, 27.33777], [88.96947, 27.30319], [89.00216, 27.32532], [88.95355, 27.4106], [88.97213, 27.51671], [89.0582, 27.60985], [89.12825, 27.62502], [89.59525, 28.16433], [89.79762, 28.23979], [90.13387, 28.19178], [90.58842, 28.02838], [90.69894, 28.07784], [91.20019, 27.98715], [91.25779, 28.07509], [91.46327, 28.0064], [91.48973, 27.93903], [91.5629, 27.84823], [91.6469, 27.76358], [91.84722, 27.76325], [91.87057, 27.7195], [92.27432, 27.89077], [92.32101, 27.79363], [92.42538, 27.80092], [92.7275, 27.98662], [92.73025, 28.05814], [92.65472, 28.07632], [92.67486, 28.15018], [92.93075, 28.25671], [93.14635, 28.37035], [93.18069, 28.50319], [93.44621, 28.67189], [93.72797, 28.68821], [94.35897, 29.01965], [94.2752, 29.11687], [94.69318, 29.31739], [94.81353, 29.17804], [95.0978, 29.14446], [95.11291, 29.09527], [95.2214, 29.10727], [95.26122, 29.07727], [95.3038, 29.13847], [95.41091, 29.13007], [95.50842, 29.13487], [95.72086, 29.20797], [95.75149, 29.32063], [95.84899, 29.31464], [96.05361, 29.38167], [96.31316, 29.18643], [96.18682, 29.11087], [96.20467, 29.02325], [96.3626, 29.10607], [96.61391, 28.72742], [96.40929, 28.51526], [96.48895, 28.42955], [96.6455, 28.61657], [96.85561, 28.4875], [96.88445, 28.39452], [96.98882, 28.32564], [97.1289, 28.3619], [97.34547, 28.21385], [97.41729, 28.29783], [97.47085, 28.2688], [97.50518, 28.49716], [97.56835, 28.55628], [97.70705, 28.5056], [97.79632, 28.33168], [97.90069, 28.3776], [98.15337, 28.12114], [98.13964, 27.9478], [98.32641, 27.51385], [98.42529, 27.55404], [98.43353, 27.67086], [98.69582, 27.56499], [98.7333, 26.85615], [98.77547, 26.61994], [98.72741, 26.36183], [98.67797, 26.24487], [98.7329, 26.17218], [98.66884, 26.09165], [98.63128, 26.15492], [98.57085, 26.11547], [98.60763, 26.01512], [98.70818, 25.86241], [98.63128, 25.79937], [98.54064, 25.85129], [98.40606, 25.61129], [98.31268, 25.55307], [98.25774, 25.6051], [98.16848, 25.62739], [98.18084, 25.56298], [98.12591, 25.50722], [98.14925, 25.41547], [97.92541, 25.20815], [97.83614, 25.2715], [97.77023, 25.11492], [97.72216, 25.08508], [97.72903, 24.91332], [97.79949, 24.85655], [97.76481, 24.8289], [97.73127, 24.83015], [97.70181, 24.84557], [97.64354, 24.79171], [97.56648, 24.76475], [97.56383, 24.75535], [97.5542, 24.74943], [97.54675, 24.74202], [97.56525, 24.72838], [97.56286, 24.54535], [97.52757, 24.43748], [97.60029, 24.4401], [97.66998, 24.45288], [97.7098, 24.35658], [97.65624, 24.33781], [97.66723, 24.30027], [97.71941, 24.29652], [97.76799, 24.26365], [97.72998, 24.2302], [97.72799, 24.18883], [97.75305, 24.16902], [97.72903, 24.12606], [97.62363, 24.00506], [97.5247, 23.94032], [97.64667, 23.84574], [97.72302, 23.89288], [97.79456, 23.94836], [97.79416, 23.95663], [97.84328, 23.97603], [97.86545, 23.97723], [97.88811, 23.97446], [97.8955, 23.97758], [97.89676, 23.97931], [97.89683, 23.98389], [97.88814, 23.98605], [97.88414, 23.99405], [97.88616, 24.00463], [97.90998, 24.02094], [97.93951, 24.01953], [97.98691, 24.03897], [97.99583, 24.04932], [98.04709, 24.07616], [98.05302, 24.07408], [98.05671, 24.07961], [98.0607, 24.07812], [98.06703, 24.08028], [98.07806, 24.07988], [98.20666, 24.11406], [98.54476, 24.13119], [98.59256, 24.08371], [98.85319, 24.13042], [98.87998, 24.15624], [98.89632, 24.10612], [98.67797, 23.9644], [98.68209, 23.80492], [98.79607, 23.77947], [98.82933, 23.72921], [98.81775, 23.694], [98.88396, 23.59555], [98.80294, 23.5345], [98.82877, 23.47908], [98.87683, 23.48995], [98.92104, 23.36946], [98.87573, 23.33038], [98.93958, 23.31414], [98.92515, 23.29535], [98.88597, 23.18656], [99.05975, 23.16382], [99.04601, 23.12215], [99.25741, 23.09025], [99.34127, 23.13099], [99.52214, 23.08218], [99.54218, 22.90014], [99.43537, 22.94086], [99.45654, 22.85726], [99.31243, 22.73893], [99.38247, 22.57544], [99.37972, 22.50188], [99.28771, 22.4105], [99.17318, 22.18025], [99.19176, 22.16983], [99.1552, 22.15874], [99.33166, 22.09656], [99.47585, 22.13345], [99.85351, 22.04183], [99.96612, 22.05965], [99.99084, 21.97053], [99.94003, 21.82782], [99.98654, 21.71064], [100.04956, 21.66843], [100.12679, 21.70539], [100.17486, 21.65306], [100.10757, 21.59945], [100.12542, 21.50365], [100.1625, 21.48704], [100.18447, 21.51898], [100.25863, 21.47043], [100.35201, 21.53176], [100.42892, 21.54325], [100.4811, 21.46148], [100.57861, 21.45637], [100.72143, 21.51898], [100.87265, 21.67396], [101.11744, 21.77659], [101.15156, 21.56129], [101.2124, 21.56422], [101.19349, 21.41959], [101.26912, 21.36482], [101.2229, 21.23271], [101.29326, 21.17254], [101.54563, 21.25668], [101.6068, 21.23329], [101.59491, 21.18621], [101.60886, 21.17947], [101.66977, 21.20004], [101.70548, 21.14911], [101.7622, 21.14813], [101.79266, 21.19025], [101.76745, 21.21571], [101.83887, 21.20983], [101.84412, 21.25291], [101.74014, 21.30967], [101.74224, 21.48276], [101.7727, 21.51794], [101.7475, 21.5873], [101.80001, 21.57461], [101.83257, 21.61562], [101.74555, 21.72852], [101.7791, 21.83019], [101.62566, 21.96574], [101.57525, 22.13026], [101.60675, 22.13513], [101.53638, 22.24794], [101.56789, 22.28876], [101.61306, 22.27515], [101.68973, 22.46843], [101.7685, 22.50337], [101.86828, 22.38397], [101.90714, 22.38688], [101.91344, 22.44417], [101.98487, 22.42766], [102.03633, 22.46164], [102.1245, 22.43372], [102.14099, 22.40092], [102.16621, 22.43336], [102.26428, 22.41321], [102.25339, 22.4607], [102.41061, 22.64184], [102.38415, 22.67919], [102.42618, 22.69212], [102.46665, 22.77108], [102.51802, 22.77969], [102.57095, 22.7036], [102.60675, 22.73376], [102.8636, 22.60735], [102.9321, 22.48659], [103.0722, 22.44775], [103.07843, 22.50097], [103.17961, 22.55705], [103.15782, 22.59873], [103.18895, 22.64471], [103.28079, 22.68063], [103.32282, 22.8127], [103.43179, 22.75816], [103.43646, 22.70648], [103.52675, 22.59155], [103.57812, 22.65764], [103.56255, 22.69499], [103.64506, 22.79979], [103.87904, 22.56683], [103.93286, 22.52703], [103.94513, 22.52553], [103.95191, 22.5134], [103.96352, 22.50584], [103.96783, 22.51173], [103.97384, 22.50634], [103.99247, 22.51958], [104.01088, 22.51823], [104.03734, 22.72945], [104.11384, 22.80363], [104.27084, 22.8457], [104.25683, 22.76534], [104.35593, 22.69353], [104.47225, 22.75813], [104.58122, 22.85571], [104.60457, 22.81841], [104.65283, 22.83419], [104.72755, 22.81984], [104.77114, 22.90017], [104.84942, 22.93631], [104.86765, 22.95178], [104.8334, 23.01484], [104.79478, 23.12934], [104.87382, 23.12854], [104.87992, 23.17141], [104.91435, 23.18666], [104.9486, 23.17235], [104.96532, 23.20463], [104.98712, 23.19176], [105.07002, 23.26248], [105.11672, 23.25247], [105.17276, 23.28679], [105.22569, 23.27249], [105.32376, 23.39684], [105.40782, 23.28107], [105.42805, 23.30824], [105.49966, 23.20669], [105.56037, 23.16806], [105.57594, 23.075], [105.72382, 23.06641], [105.8726, 22.92756], [105.90119, 22.94168], [105.99568, 22.94178], [106.00179, 22.99049], [106.19705, 22.98475], [106.27022, 22.87722], [106.34961, 22.86718], [106.49749, 22.91164], [106.51306, 22.94891], [106.55976, 22.92311], [106.60179, 22.92884], [106.6516, 22.86862], [106.6734, 22.89587], [106.71387, 22.88296], [106.71128, 22.85982], [106.78422, 22.81532], [106.81271, 22.8226], [106.83685, 22.8098], [106.82404, 22.7881], [106.76293, 22.73491], [106.72321, 22.63606], [106.71698, 22.58432], [106.65316, 22.5757], [106.61269, 22.60301], [106.58395, 22.474], [106.55665, 22.46498], [106.57221, 22.37], [106.55976, 22.34841], [106.6516, 22.33977], [106.69986, 22.22309], [106.67495, 22.1885], [106.6983, 22.15102], [106.70142, 22.02409], [106.68274, 21.99811], [106.69276, 21.96013], [106.72551, 21.97923], [106.74345, 22.00965], [106.81038, 21.97934], [106.9178, 21.97357], [106.92714, 21.93459], [106.97228, 21.92592], [106.99252, 21.95191], [107.05634, 21.92303], [107.06101, 21.88982], [107.00964, 21.85948], [107.02615, 21.81981], [107.10771, 21.79879], [107.20734, 21.71493], [107.24625, 21.7077], [107.29296, 21.74674], [107.35834, 21.6672], [107.35989, 21.60063], [107.38636, 21.59774], [107.41593, 21.64839], [107.47197, 21.6672], [107.49532, 21.62958], [107.49065, 21.59774], [107.54047, 21.5934], [107.56537, 21.61945], [107.66967, 21.60787], [107.80355, 21.66141], [107.86114, 21.65128], [107.90006, 21.5905], [107.92652, 21.58906], [107.95232, 21.5388], [107.96774, 21.53601], [107.97074, 21.54072], [107.97383, 21.53961], [107.97932, 21.54503], [108.02926, 21.54997], [108.0569, 21.53604], [108.10003, 21.47338], [108.00365, 17.98159], [111.60491, 13.57105], [118.41371, 24.06775], [118.11703, 24.39734], [118.28244, 24.51231], [118.35291, 24.51645], [118.42453, 24.54644], [118.6333, 24.46259], [119.42295, 25.0886], [119.98511, 25.37624], [119.78816, 26.2348], [120.0693, 26.3959], [120.5128, 26.536], [121.03532, 26.8787], [123.5458, 31.01942], [122.29378, 31.76513], [122.80525, 33.30571], [123.85601, 37.49093], [123.90497, 38.79949], [124.17532, 39.8232], [124.23201, 39.9248], [124.35029, 39.95639], [124.37089, 40.03004], [124.3322, 40.05573], [124.38556, 40.11047], [124.40719, 40.13655], [124.86913, 40.45387], [125.71172, 40.85223], [125.76869, 40.87908], [126.00335, 40.92835], [126.242, 41.15454], [126.53189, 41.35206], [126.60631, 41.65565], [126.90729, 41.79955], [127.17841, 41.59714], [127.29712, 41.49473], [127.92943, 41.44291], [128.02633, 41.42103], [128.03311, 41.39232], [128.12967, 41.37931], [128.18546, 41.41279], [128.20061, 41.40895], [128.30716, 41.60322], [128.15119, 41.74568], [128.04487, 42.01769], [128.94007, 42.03537], [128.96068, 42.06657], [129.15178, 42.17224], [129.22285, 42.26491], [129.22423, 42.3553], [129.28541, 42.41574], [129.42882, 42.44702], [129.54701, 42.37254], [129.60482, 42.44461], [129.72541, 42.43739], [129.75294, 42.59409], [129.77183, 42.69435], [129.7835, 42.76521], [129.80719, 42.79218], [129.83277, 42.86746], [129.85261, 42.96494], [129.8865, 43.00395], [129.95082, 43.01051], [129.96409, 42.97306], [130.12957, 42.98361], [130.09764, 42.91425], [130.26095, 42.9027], [130.23068, 42.80125], [130.2385, 42.71127], [130.41826, 42.6011], [130.44361, 42.54849], [130.50123, 42.61636], [130.55143, 42.52158], [130.62107, 42.58413], [130.56576, 42.68925], [130.40213, 42.70788], [130.44361, 42.76205], [130.66524, 42.84753], [131.02438, 42.86518], [131.02668, 42.91246], [131.135, 42.94114], [131.10274, 43.04734], [131.20414, 43.13654], [131.19031, 43.21385], [131.30324, 43.39498], [131.29402, 43.46695], [131.19492, 43.53047], [131.21105, 43.82383], [131.26176, 43.94011], [131.23583, 43.96085], [131.25484, 44.03131], [131.30365, 44.04262], [131.1108, 44.70266], [130.95639, 44.85154], [131.48415, 44.99513], [131.68466, 45.12374], [131.66852, 45.2196], [131.76532, 45.22609], [131.86903, 45.33636], [131.99417, 45.2567], [132.83978, 45.05916], [132.96373, 45.0212], [133.12293, 45.1332], [133.09279, 45.25693], [133.19419, 45.51913], [133.41083, 45.57723], [133.48457, 45.86203], [133.60442, 45.90053], [133.67569, 45.9759], [133.72695, 46.05576], [133.68047, 46.14697], [133.88097, 46.25066], [133.91496, 46.4274], [133.84104, 46.46681], [134.03538, 46.75668], [134.20016, 47.33458], [134.50898, 47.4812], [134.7671, 47.72051], [134.55508, 47.98651], [134.67098, 48.1564], [134.75328, 48.36763], [134.49516, 48.42884], [132.66989, 47.96491], [132.57309, 47.71741], [131.90448, 47.68011], [131.2635, 47.73325], [131.09871, 47.6852], [130.95985, 47.6957], [130.90915, 47.90623], [130.65103, 48.10052], [130.84462, 48.30942], [130.52147, 48.61745], [130.66946, 48.88251], [130.43232, 48.90844], [130.2355, 48.86741], [129.85416, 49.11067], [129.67598, 49.29596], [129.50685, 49.42398], [129.40398, 49.44194], [129.35317, 49.3481], [129.23232, 49.40353], [129.11153, 49.36813], [128.72896, 49.58676], [127.83476, 49.5748], [127.53516, 49.84306], [127.49299, 50.01251], [127.60515, 50.23503], [127.37384, 50.28393], [127.36009, 50.43787], [127.28765, 50.46585], [127.36335, 50.58306], [127.28165, 50.72075], [127.14586, 50.91152], [126.93135, 51.0841], [126.90369, 51.3238], [126.68349, 51.70607], [126.44606, 51.98254], [126.558, 52.13738], [125.6131, 53.07229]], [[113.56865, 22.20973], [113.57123, 22.20416], [113.60504, 22.20464], [113.63011, 22.10782], [113.57191, 22.07696], [113.54839, 22.10909], [113.54942, 22.14519], [113.54093, 22.15497], [113.52659, 22.18271], [113.53552, 22.20607], [113.53301, 22.21235], [113.53591, 22.21369], [113.54093, 22.21314], [113.54333, 22.21688], [113.5508, 22.21672], [113.56865, 22.20973]], [[114.50148, 22.15017], [113.92195, 22.13873], [113.83338, 22.1826], [113.81621, 22.2163], [113.86771, 22.42972], [114.03113, 22.5065], [114.05438, 22.5026], [114.05729, 22.51104], [114.06272, 22.51617], [114.07267, 22.51855], [114.07817, 22.52997], [114.08606, 22.53276], [114.09048, 22.53716], [114.09692, 22.53435], [114.1034, 22.5352], [114.11181, 22.52878], [114.11656, 22.53415], [114.12665, 22.54003], [114.13823, 22.54319], [114.1482, 22.54091], [114.15123, 22.55163], [114.1597, 22.56041], [114.17247, 22.55944], [114.18338, 22.55444], [114.20655, 22.55706], [114.22185, 22.55343], [114.22888, 22.5436], [114.25154, 22.55977], [114.44998, 22.55977], [114.50148, 22.15017]]]] } },
     { type: "Feature", properties: { wikidata: "Q22890", nameEn: "Ireland", level: "sharedLandform" }, geometry: null },
     { type: "Feature", properties: { wikidata: "Q23666", nameEn: "Great Britain", country: "GB", level: "sharedLandform" }, geometry: null },
     { type: "Feature", properties: { wikidata: "Q23681", nameEn: "Northern Cyprus", groups: ["Q644636", "145", "142"], driveSide: "left", callingCodes: ["90 392"] }, geometry: { type: "MultiPolygon", coordinates: [[[[33.67678, 35.03866], [33.67742, 35.05963], [33.68474, 35.06602], [33.69095, 35.06237], [33.70861, 35.07644], [33.7161, 35.07279], [33.70209, 35.04882], [33.71482, 35.03722], [33.73824, 35.05321], [33.76106, 35.04253], [33.78581, 35.05104], [33.82067, 35.07826], [33.84168, 35.06823], [33.8541, 35.07201], [33.87479, 35.08881], [33.87097, 35.09389], [33.87622, 35.10457], [33.87224, 35.12293], [33.88561, 35.12449], [33.88943, 35.12007], [33.88737, 35.11408], [33.89853, 35.11377], [33.91789, 35.08688], [33.91299, 35.07579], [33.90247, 35.07686], [33.89485, 35.06873], [33.88367, 35.07877], [33.85261, 35.0574], [33.8355, 35.05777], [33.82051, 35.0667], [33.8012, 35.04786], [33.81524, 35.04192], [33.83055, 35.02865], [33.82875, 35.01685], [33.84045, 35.00616], [33.85216, 35.00579], [33.85891, 35.001], [33.85621, 34.98956], [33.83505, 34.98108], [33.84811, 34.97075], [33.86432, 34.97592], [33.90075, 34.96623], [33.98684, 34.76642], [35.48515, 34.70851], [35.51152, 36.10954], [32.82353, 35.70297], [32.46489, 35.48584], [32.60361, 35.16647], [32.64864, 35.19967], [32.70947, 35.18328], [32.70779, 35.14127], [32.85733, 35.07742], [32.86406, 35.1043], [32.94471, 35.09422], [33.01192, 35.15639], [33.08249, 35.17319], [33.11105, 35.15639], [33.15138, 35.19504], [33.27068, 35.16815], [33.3072, 35.16816], [33.31955, 35.18096], [33.35056, 35.18328], [33.34964, 35.17803], [33.35596, 35.17942], [33.35612, 35.17402], [33.36569, 35.17479], [33.3717, 35.1788], [33.37248, 35.18698], [33.38575, 35.2018], [33.4076, 35.20062], [33.41675, 35.16325], [33.46813, 35.10564], [33.48136, 35.0636], [33.47825, 35.04103], [33.45178, 35.02078], [33.45256, 35.00288], [33.47666, 35.00701], [33.48915, 35.06594], [33.53975, 35.08151], [33.57478, 35.06049], [33.567, 35.04803], [33.59658, 35.03635], [33.61215, 35.0527], [33.63765, 35.03869], [33.67678, 35.03866]]]] } },
     { type: "Feature", properties: { m49: "155", wikidata: "Q27496", nameEn: "Western Europe", level: "subregion" }, geometry: null },
     { type: "Feature", properties: { m49: "202", wikidata: "Q132959", nameEn: "Sub-Saharan Africa", level: "subregion" }, geometry: null },
     { type: "Feature", properties: { m49: "419", wikidata: "Q72829598", nameEn: "Latin America and the Caribbean", level: "subregion" }, geometry: null },
-    { type: "Feature", properties: { m49: "680", wikidata: "Q3405693", nameEn: "Sark", country: "GB", groups: ["GG", "830", "Q185086", "154", "150", "UN"], level: "subterritory", driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44 01481"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-2.36485, 49.48223], [-2.65349, 49.15373], [-2.09454, 49.46288], [-2.36485, 49.48223]]]] } },
     { type: "Feature", properties: { m49: "830", wikidata: "Q42314", nameEn: "Channel Islands", level: "intermediateRegion" }, geometry: null },
     { type: "Feature", properties: { iso1A2: "AC", iso1A3: "ASC", wikidata: "Q46197", nameEn: "Ascension Island", aliases: ["SH-AC"], country: "GB", groups: ["SH", "BOTS", "011", "202", "002", "UN"], isoStatus: "excRes", driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["247"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-14.82771, -8.70814], [-13.33271, -8.07391], [-14.91926, -6.63386], [-14.82771, -8.70814]]]] } },
     { type: "Feature", properties: { iso1A2: "AD", iso1A3: "AND", iso1N3: "020", wikidata: "Q228", nameEn: "Andorra", groups: ["Q12837", "039", "150", "UN"], callingCodes: ["376"] }, geometry: { type: "MultiPolygon", coordinates: [[[[1.72515, 42.50338], [1.73683, 42.55492], [1.7858, 42.57698], [1.72588, 42.59098], [1.73452, 42.61515], [1.68267, 42.62533], [1.6625, 42.61982], [1.63485, 42.62957], [1.60085, 42.62703], [1.55418, 42.65669], [1.50867, 42.64483], [1.48043, 42.65203], [1.46718, 42.63296], [1.47986, 42.61346], [1.44197, 42.60217], [1.42512, 42.58292], [1.44529, 42.56722], [1.4234, 42.55959], [1.41245, 42.53539], [1.44759, 42.54431], [1.46661, 42.50949], [1.41648, 42.48315], [1.43838, 42.47848], [1.44529, 42.43724], [1.5127, 42.42959], [1.55073, 42.43299], [1.55937, 42.45808], [1.57953, 42.44957], [1.58933, 42.46275], [1.65674, 42.47125], [1.66826, 42.50779], [1.70571, 42.48867], [1.72515, 42.50338]]]] } },
     { type: "Feature", properties: { iso1A2: "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: "CN", iso1A3: "CHN", iso1N3: "156", wikidata: "Q148", nameEn: "People's Republic of China" }, geometry: null },
     { type: "Feature", properties: { iso1A2: "CO", iso1A3: "COL", iso1N3: "170", wikidata: "Q739", nameEn: "Colombia", groups: ["005", "419", "019", "UN"], callingCodes: ["57"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-71.19849, 12.65801], [-81.58685, 18.0025], [-82.06974, 14.49418], [-82.56142, 11.91792], [-78.79327, 9.93766], [-77.58292, 9.22278], [-77.32389, 8.81247], [-77.45064, 8.49991], [-77.17257, 7.97422], [-77.57185, 7.51147], [-77.72514, 7.72348], [-77.72157, 7.47612], [-77.81426, 7.48319], [-77.89178, 7.22681], [-78.06168, 7.07793], [-82.12561, 4.00341], [-78.87137, 1.47457], [-78.42749, 1.15389], [-77.85677, 0.80197], [-77.7148, 0.85003], [-77.68613, 0.83029], [-77.66416, 0.81604], [-77.67815, 0.73863], [-77.49984, 0.64476], [-77.52001, 0.40782], [-76.89177, 0.24736], [-76.4094, 0.24015], [-76.41215, 0.38228], [-76.23441, 0.42294], [-75.82927, 0.09578], [-75.25764, -0.11943], [-75.18513, -0.0308], [-74.42701, -0.50218], [-74.26675, -0.97229], [-73.65312, -1.26222], [-72.92587, -2.44514], [-71.75223, -2.15058], [-70.94377, -2.23142], [-70.04609, -2.73906], [-70.71396, -3.7921], [-70.52393, -3.87553], [-70.3374, -3.79505], [-69.94708, -4.2431], [-69.43395, -1.42219], [-69.4215, -1.01853], [-69.59796, -0.75136], [-69.603, -0.51947], [-70.03658, -0.19681], [-70.04162, 0.55437], [-69.47696, 0.71065], [-69.20976, 0.57958], [-69.14422, 0.84172], [-69.26017, 1.06856], [-69.82987, 1.07864], [-69.83491, 1.69353], [-69.53746, 1.76408], [-69.38621, 1.70865], [-68.18128, 1.72881], [-68.26699, 1.83463], [-68.18632, 2.00091], [-67.9292, 1.82455], [-67.40488, 2.22258], [-67.299, 1.87494], [-67.15784, 1.80439], [-67.08222, 1.17441], [-66.85795, 1.22998], [-67.21967, 2.35778], [-67.65696, 2.81691], [-67.85862, 2.79173], [-67.85862, 2.86727], [-67.30945, 3.38393], [-67.50067, 3.75812], [-67.62671, 3.74303], [-67.85358, 4.53249], [-67.83341, 5.31104], [-67.59141, 5.5369], [-67.63914, 5.64963], [-67.58558, 5.84537], [-67.43513, 5.98835], [-67.4625, 6.20625], [-67.60654, 6.2891], [-69.41843, 6.1072], [-70.10716, 6.96516], [-70.7596, 7.09799], [-71.03941, 6.98163], [-71.37234, 7.01588], [-71.42212, 7.03854], [-71.44118, 7.02116], [-71.82441, 7.04314], [-72.04895, 7.03837], [-72.19437, 7.37034], [-72.43132, 7.40034], [-72.47415, 7.48928], [-72.45321, 7.57232], [-72.47827, 7.65604], [-72.46763, 7.79518], [-72.44454, 7.86031], [-72.46183, 7.90682], [-72.45806, 7.91141], [-72.47042, 7.92306], [-72.48183, 7.92909], [-72.48801, 7.94329], [-72.47213, 7.96106], [-72.39137, 8.03534], [-72.35163, 8.01163], [-72.36987, 8.19976], [-72.4042, 8.36513], [-72.65474, 8.61428], [-72.77415, 9.10165], [-72.94052, 9.10663], [-73.02119, 9.27584], [-73.36905, 9.16636], [-72.98085, 9.85253], [-72.88002, 10.44309], [-72.4767, 11.1117], [-72.24983, 11.14138], [-71.9675, 11.65536], [-71.3275, 11.85], [-70.92579, 11.96275], [-71.19849, 12.65801]]]] } },
     { type: "Feature", properties: { iso1A2: "CP", iso1A3: "CPT", wikidata: "Q161258", nameEn: "Clipperton Island", country: "FR", groups: ["EU", "013", "003", "019", "UN"], isoStatus: "excRes" }, geometry: { type: "MultiPolygon", coordinates: [[[[-110.36279, 9.79626], [-108.755, 9.84085], [-109.04145, 11.13245], [-110.36279, 9.79626]]]] } },
+    { type: "Feature", properties: { iso1A2: "CQ", iso1A3: "CRQ", iso1N3: "680", m49: "680", wikidata: "Q3405693", ccTLD: null, nameEn: "Sark", country: "GB", groups: ["GG", "830", "Q185086", "154", "150", "UN"], level: "subterritory", isoStatus: "excRes", driveSide: "left", roadSpeedUnit: "mph", roadHeightUnit: "ft", callingCodes: ["44 01481"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-2.36485, 49.48223], [-2.65349, 49.15373], [-2.09454, 49.46288], [-2.36485, 49.48223]]]] } },
     { type: "Feature", properties: { iso1A2: "CR", iso1A3: "CRI", iso1N3: "188", wikidata: "Q800", nameEn: "Costa Rica", groups: ["013", "003", "419", "019", "UN"], callingCodes: ["506"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-83.68276, 11.01562], [-83.66597, 10.79916], [-83.90838, 10.71161], [-84.68197, 11.07568], [-84.92439, 10.9497], [-85.60529, 11.22607], [-85.71223, 11.06868], [-86.14524, 11.09059], [-87.41779, 5.02401], [-82.94503, 7.93865], [-82.89978, 8.04083], [-82.89137, 8.05755], [-82.88641, 8.10219], [-82.9388, 8.26634], [-83.05209, 8.33394], [-82.93056, 8.43465], [-82.8679, 8.44042], [-82.8382, 8.48117], [-82.83322, 8.52464], [-82.83975, 8.54755], [-82.82739, 8.60153], [-82.8794, 8.6981], [-82.92068, 8.74832], [-82.91377, 8.774], [-82.88253, 8.83331], [-82.72126, 8.97125], [-82.93516, 9.07687], [-82.93516, 9.46741], [-82.84871, 9.4973], [-82.87919, 9.62645], [-82.77206, 9.59573], [-82.66667, 9.49746], [-82.61345, 9.49881], [-82.56507, 9.57279], [-82.51044, 9.65379], [-83.54024, 10.96805], [-83.68276, 11.01562]]]] } },
     { type: "Feature", properties: { iso1A2: "CU", iso1A3: "CUB", iso1N3: "192", wikidata: "Q241", nameEn: "Cuba", groups: ["029", "003", "419", "019", "UN"], callingCodes: ["53"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-73.62304, 20.6935], [-82.02215, 24.23074], [-85.77883, 21.92705], [-74.81171, 18.82201], [-73.62304, 20.6935]]]] } },
     { type: "Feature", properties: { iso1A2: "CV", iso1A3: "CPV", iso1N3: "132", wikidata: "Q1011", nameEn: "Cape Verde", groups: ["Q105472", "011", "202", "002", "UN"], callingCodes: ["238"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-28.81604, 14.57305], [-20.39702, 14.12816], [-23.37101, 19.134], [-28.81604, 14.57305]]]] } },
     { 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: "TR", iso1A3: "TUR", iso1N3: "792", wikidata: "Q43", nameEn: "Turkey", groups: ["145", "142", "UN"], callingCodes: ["90"] }, geometry: { type: "MultiPolygon", coordinates: [[[[41.54366, 41.52185], [40.89217, 41.72528], [34.8305, 42.4581], [28.32297, 41.98371], [28.02971, 41.98066], [27.91479, 41.97902], [27.83492, 41.99709], [27.81235, 41.94803], [27.69949, 41.97515], [27.55191, 41.90928], [27.52379, 41.93756], [27.45478, 41.96591], [27.27411, 42.10409], [27.22376, 42.10152], [27.19251, 42.06028], [27.08486, 42.08735], [27.03277, 42.0809], [26.95638, 42.00741], [26.79143, 41.97386], [26.62996, 41.97644], [26.56051, 41.92995], [26.57961, 41.90024], [26.53968, 41.82653], [26.36952, 41.82265], [26.33589, 41.76802], [26.32952, 41.73637], [26.35957, 41.71149], [26.47958, 41.67037], [26.5209, 41.62592], [26.59196, 41.60491], [26.59742, 41.48058], [26.61767, 41.42281], [26.62997, 41.34613], [26.5837, 41.32131], [26.5209, 41.33993], [26.39861, 41.25053], [26.32259, 41.24929], [26.31928, 41.07386], [26.3606, 41.02027], [26.33297, 40.98388], [26.35894, 40.94292], [26.32259, 40.94042], [26.28623, 40.93005], [26.29441, 40.89119], [26.26169, 40.9168], [26.20856, 40.86048], [26.21351, 40.83298], [26.15685, 40.80709], [26.12854, 40.77339], [26.12495, 40.74283], [26.08638, 40.73214], [26.0754, 40.72772], [26.03489, 40.73051], [25.94795, 40.72797], [26.04292, 40.3958], [25.61285, 40.17161], [25.94257, 39.39358], [26.43357, 39.43096], [26.70773, 39.0312], [26.61814, 38.81372], [26.21136, 38.65436], [26.32173, 38.48731], [26.24183, 38.44695], [26.21136, 38.17558], [27.05537, 37.9131], [27.16428, 37.72343], [26.99377, 37.69034], [26.95583, 37.64989], [27.14757, 37.32], [27.20312, 36.94571], [27.45627, 36.9008], [27.24613, 36.71622], [27.46117, 36.53789], [27.89482, 36.69898], [27.95037, 36.46155], [28.23708, 36.56812], [29.30783, 36.01033], [29.48192, 36.18377], [29.61002, 36.1731], [29.61805, 36.14179], [29.69611, 36.10365], [29.73302, 35.92555], [32.82353, 35.70297], [35.51152, 36.10954], [35.931, 35.92109], [35.98499, 35.94107], [36.00514, 35.94113], [36.01844, 35.92403], [35.99829, 35.88242], [36.11827, 35.85923], [36.13919, 35.83692], [36.14029, 35.81015], [36.1623, 35.80925], [36.17441, 35.92076], [36.19973, 35.95195], [36.25366, 35.96264], [36.27678, 35.94839], [36.29769, 35.96086], [36.28338, 36.00273], [36.30099, 36.00985], [36.33956, 35.98687], [36.37474, 36.01163], [36.39206, 36.22088], [36.4617, 36.20461], [36.50463, 36.2419], [36.6125, 36.22592], [36.68672, 36.23677], [36.65653, 36.33861], [36.6081, 36.33772], [36.54206, 36.49539], [36.58829, 36.58295], [36.57398, 36.65186], [36.62681, 36.71189], [36.61581, 36.74629], [36.66727, 36.82901], [36.99557, 36.75997], [36.99886, 36.74012], [37.04399, 36.73483], [37.04619, 36.71101], [37.01647, 36.69512], [37.02088, 36.66422], [37.08279, 36.63495], [37.10894, 36.6704], [37.16177, 36.66069], [37.21988, 36.6736], [37.47253, 36.63243], [37.49103, 36.66904], [37.68048, 36.75065], [37.81974, 36.76055], [38.21064, 36.91842], [38.38859, 36.90064], [38.55908, 36.84429], [38.74042, 36.70629], [39.03217, 36.70911], [39.21538, 36.66834], [39.81589, 36.75538], [40.69136, 37.0996], [40.90856, 37.13147], [41.21937, 37.07665], [41.515, 37.08084], [42.00894, 37.17209], [42.18225, 37.28569], [42.19301, 37.31323], [42.2112, 37.32491], [42.22257, 37.31395], [42.22381, 37.30238], [42.20454, 37.28715], [42.21548, 37.28026], [42.23683, 37.2863], [42.26039, 37.27017], [42.2824, 37.2798], [42.34735, 37.22548], [42.32313, 37.17814], [42.35724, 37.10998], [42.56725, 37.14878], [42.78887, 37.38615], [42.93705, 37.32015], [43.11403, 37.37436], [43.30083, 37.30629], [43.33508, 37.33105], [43.50787, 37.24436], [43.56702, 37.25675], [43.63085, 37.21957], [43.7009, 37.23692], [43.8052, 37.22825], [43.82699, 37.19477], [43.84878, 37.22205], [43.90949, 37.22453], [44.02002, 37.33229], [44.13521, 37.32486], [44.2613, 37.25055], [44.27998, 37.16501], [44.22239, 37.15756], [44.18503, 37.09551], [44.25975, 36.98119], [44.30645, 36.97373], [44.35937, 37.02843], [44.35315, 37.04955], [44.38117, 37.05825], [44.42631, 37.05825], [44.63179, 37.19229], [44.76698, 37.16162], [44.78319, 37.1431], [44.7868, 37.16644], [44.75986, 37.21549], [44.81021, 37.2915], [44.58449, 37.45018], [44.61401, 37.60165], [44.56887, 37.6429], [44.62096, 37.71985], [44.55498, 37.783], [44.45948, 37.77065], [44.3883, 37.85433], [44.22509, 37.88859], [44.42476, 38.25763], [44.50115, 38.33939], [44.44386, 38.38295], [44.38309, 38.36117], [44.3119, 38.37887], [44.3207, 38.49799], [44.32058, 38.62752], [44.28065, 38.6465], [44.26155, 38.71427], [44.30322, 38.81581], [44.18863, 38.93881], [44.20946, 39.13975], [44.1043, 39.19842], [44.03667, 39.39223], [44.22452, 39.4169], [44.29818, 39.378], [44.37921, 39.4131], [44.42832, 39.4131], [44.41849, 39.56659], [44.48111, 39.61579], [44.47298, 39.68788], [44.6137, 39.78393], [44.65422, 39.72163], [44.71806, 39.71124], [44.81043, 39.62677], [44.80977, 39.65768], [44.75779, 39.7148], [44.61845, 39.8281], [44.46635, 39.97733], [44.26973, 40.04866], [44.1778, 40.02845], [44.1057, 40.03555], [43.92307, 40.01787], [43.65688, 40.11199], [43.65221, 40.14889], [43.71136, 40.16673], [43.59928, 40.34019], [43.60862, 40.43267], [43.54791, 40.47413], [43.63664, 40.54159], [43.7425, 40.66805], [43.74872, 40.7365], [43.67712, 40.84846], [43.67712, 40.93084], [43.58683, 40.98961], [43.47319, 41.02251], [43.44984, 41.0988], [43.4717, 41.12611], [43.44973, 41.17666], [43.36118, 41.2028], [43.23096, 41.17536], [43.1945, 41.25242], [43.13373, 41.25503], [43.21707, 41.30331], [43.02956, 41.37891], [42.8785, 41.50516], [42.84899, 41.47265], [42.78995, 41.50126], [42.84471, 41.58912], [42.72794, 41.59714], [42.59202, 41.58183], [42.51772, 41.43606], [42.26387, 41.49346], [41.95134, 41.52466], [41.81939, 41.43621], [41.7124, 41.47417], [41.7148, 41.4932], [41.54366, 41.52185]]]] } },
     { type: "Feature", properties: { iso1A2: "TT", iso1A3: "TTO", iso1N3: "780", wikidata: "Q754", nameEn: "Trinidad and Tobago", groups: ["029", "003", "419", "019", "UN"], driveSide: "left", callingCodes: ["1 868"] }, geometry: { type: "MultiPolygon", coordinates: [[[[-61.62505, 11.18974], [-62.08693, 10.04435], [-60.89962, 9.81445], [-60.07172, 11.77667], [-61.62505, 11.18974]]]] } },
     { type: "Feature", properties: { iso1A2: "TV", iso1A3: "TUV", iso1N3: "798", wikidata: "Q672", nameEn: "Tuvalu", groups: ["061", "009", "UN"], driveSide: "left", callingCodes: ["688"] }, geometry: { type: "MultiPolygon", coordinates: [[[[174, -5], [174, -11.5], [179.99999, -11.5], [179.99999, -5], [174, -5]]]] } },
-    { type: "Feature", properties: { iso1A2: "TW", iso1A3: "TWN", iso1N3: "158", wikidata: "Q865", nameEn: "Taiwan", aliases: ["RC"], groups: ["030", "142"], callingCodes: ["886"] }, geometry: { type: "MultiPolygon", coordinates: [[[[121.8109, 21.77688], [122.26612, 25.98197], [120.49232, 25.22863], [118.56434, 24.49266], [118.42453, 24.54644], [118.35291, 24.51645], [118.28244, 24.51231], [118.11703, 24.39734], [120.69238, 21.52331], [121.8109, 21.77688]]]] } },
+    { type: "Feature", properties: { iso1A2: "TW", iso1A3: "TWN", iso1N3: "158", wikidata: "Q865", nameEn: "Taiwan", aliases: ["RC"], groups: ["030", "142"], callingCodes: ["886"] }, geometry: { type: "MultiPolygon", coordinates: [[[[121.8109, 21.77688], [122.26612, 25.98197], [120.5128, 26.536], [120.0693, 26.3959], [119.78816, 26.2348], [119.98511, 25.37624], [119.42295, 25.0886], [118.6333, 24.46259], [118.42453, 24.54644], [118.35291, 24.51645], [118.28244, 24.51231], [118.11703, 24.39734], [120.69238, 21.52331], [121.8109, 21.77688]]]] } },
     { type: "Feature", properties: { iso1A2: "TZ", iso1A3: "TZA", iso1N3: "834", wikidata: "Q924", nameEn: "Tanzania", groups: ["014", "202", "002", "UN"], driveSide: "left", callingCodes: ["255"] }, geometry: { type: "MultiPolygon", coordinates: [[[[30.80408, -0.99911], [30.76635, -0.9852], [30.70631, -1.01175], [30.64166, -1.06601], [30.47194, -1.0555], [30.45116, -1.10641], [30.50889, -1.16412], [30.57123, -1.33264], [30.71974, -1.43244], [30.84079, -1.64652], [30.80802, -1.91477], [30.89303, -2.08223], [30.83915, -2.35795], [30.54501, -2.41404], [30.41789, -2.66266], [30.52747, -2.65841], [30.40662, -2.86151], [30.4987, -2.9573], [30.57926, -2.89791], [30.6675, -2.98987], [30.83823, -2.97837], [30.84165, -3.25152], [30.45915, -3.56532], [30.22042, -4.01738], [30.03323, -4.26631], [29.88172, -4.35743], [29.82885, -4.36153], [29.77289, -4.41733], [29.75109, -4.45836], [29.63827, -4.44681], [29.43673, -4.44845], [29.52552, -6.2731], [30.2567, -7.14121], [30.79243, -8.27382], [31.00796, -8.58615], [31.37533, -8.60769], [31.57147, -8.70619], [31.57147, -8.81388], [31.71158, -8.91386], [31.81587, -8.88618], [31.94663, -8.93846], [31.94196, -9.02303], [31.98866, -9.07069], [32.08206, -9.04609], [32.16146, -9.05993], [32.25486, -9.13371], [32.43543, -9.11988], [32.49147, -9.14754], [32.53661, -9.24281], [32.75611, -9.28583], [32.76233, -9.31963], [32.95389, -9.40138], [32.99397, -9.36712], [33.14925, -9.49322], [33.31581, -9.48554], [33.48052, -9.62442], [33.76677, -9.58516], [33.93298, -9.71647], [33.9638, -9.62206], [33.95829, -9.54066], [34.03865, -9.49398], [34.54499, -10.0678], [34.51911, -10.12279], [34.57581, -10.56271], [34.65946, -10.6828], [34.67047, -10.93796], [34.61161, -11.01611], [34.63305, -11.11731], [34.79375, -11.32245], [34.91153, -11.39799], [34.96296, -11.57354], [35.63599, -11.55927], [35.82767, -11.41081], [36.19094, -11.57593], [36.19094, -11.70008], [36.62068, -11.72884], [36.80309, -11.56836], [37.3936, -11.68949], [37.76614, -11.53352], [37.8388, -11.3123], [37.93618, -11.26228], [38.21598, -11.27289], [38.47258, -11.4199], [38.88996, -11.16978], [39.24395, -11.17433], [39.58249, -10.96043], [40.00295, -10.80255], [40.44265, -10.4618], [40.74206, -10.25691], [40.14328, -4.64201], [39.62121, -4.68136], [39.44306, -4.93877], [39.21631, -4.67835], [37.81321, -3.69179], [37.75036, -3.54243], [37.63099, -3.50723], [37.5903, -3.42735], [37.71745, -3.304], [37.67199, -3.06222], [34.0824, -1.02264], [34.03084, -1.05101], [34.02286, -1.00779], [33.93107, -0.99298], [30.80408, -0.99911]]]] } },
     { type: "Feature", properties: { iso1A2: "UA", iso1A3: "UKR", iso1N3: "804", wikidata: "Q212", nameEn: "Ukraine", groups: ["151", "150", "UN"], callingCodes: ["380"] }, geometry: { type: "MultiPolygon", coordinates: [[[[33.57318, 46.10317], [33.61467, 46.13561], [33.63854, 46.14147], [33.61517, 46.22615], [33.646, 46.23028], [33.74047, 46.18555], [33.79715, 46.20482], [33.85234, 46.19863], [33.91549, 46.15938], [34.05272, 46.10838], [34.07311, 46.11769], [34.12929, 46.10494], [34.181, 46.06804], [34.25111, 46.0532], [34.33912, 46.06114], [34.41221, 46.00245], [34.44155, 45.95995], [34.48729, 45.94267], [34.52011, 45.95097], [34.55889, 45.99347], [34.60861, 45.99347], [34.66679, 45.97136], [34.75479, 45.90705], [34.80153, 45.90047], [34.79905, 45.81009], [34.96015, 45.75634], [35.23066, 45.79231], [37.62608, 46.82615], [38.12112, 46.86078], [38.3384, 46.98085], [38.22955, 47.12069], [38.23049, 47.2324], [38.32112, 47.2585], [38.33074, 47.30508], [38.22225, 47.30788], [38.28954, 47.39255], [38.28679, 47.53552], [38.35062, 47.61631], [38.76379, 47.69346], [38.79628, 47.81109], [38.87979, 47.87719], [39.73935, 47.82876], [39.82213, 47.96396], [39.77544, 48.04206], [39.88256, 48.04482], [39.83724, 48.06501], [39.94847, 48.22811], [40.00752, 48.22445], [39.99241, 48.31768], [39.97325, 48.31399], [39.9693, 48.29904], [39.95248, 48.29972], [39.91465, 48.26743], [39.90041, 48.3049], [39.84273, 48.30947], [39.84136, 48.33321], [39.94847, 48.35055], [39.88794, 48.44226], [39.86196, 48.46633], [39.84548, 48.57821], [39.79764, 48.58668], [39.67226, 48.59368], [39.71765, 48.68673], [39.73104, 48.7325], [39.79466, 48.83739], [39.97182, 48.79398], [40.08168, 48.87443], [40.03636, 48.91957], [39.98967, 48.86901], [39.78368, 48.91596], [39.74874, 48.98675], [39.72649, 48.9754], [39.71353, 48.98959], [39.6683, 48.99454], [39.6836, 49.05121], [39.93437, 49.05709], [40.01988, 49.1761], [40.22176, 49.25683], [40.18331, 49.34996], [40.14912, 49.37681], [40.1141, 49.38798], [40.03087, 49.45452], [40.03636, 49.52321], [40.16683, 49.56865], [40.13249, 49.61672], [39.84548, 49.56064], [39.65047, 49.61761], [39.59142, 49.73758], [39.44496, 49.76067], [39.27968, 49.75976], [39.1808, 49.88911], [38.9391, 49.79524], [38.90477, 49.86787], [38.73311, 49.90238], [38.68677, 50.00904], [38.65688, 49.97176], [38.35408, 50.00664], [38.32524, 50.08866], [38.18517, 50.08161], [38.21675, 49.98104], [38.02999, 49.90592], [38.02999, 49.94482], [37.90776, 50.04194], [37.79515, 50.08425], [37.75807, 50.07896], [37.61113, 50.21976], [37.62879, 50.24481], [37.62486, 50.29966], [37.47243, 50.36277], [37.48204, 50.46079], [37.08468, 50.34935], [36.91762, 50.34963], [36.69377, 50.26982], [36.64571, 50.218], [36.56655, 50.2413], [36.58371, 50.28563], [36.47817, 50.31457], [36.30101, 50.29088], [36.20763, 50.3943], [36.06893, 50.45205], [35.8926, 50.43829], [35.80388, 50.41356], [35.73659, 50.35489], [35.61711, 50.35707], [35.58003, 50.45117], [35.47463, 50.49247], [35.39464, 50.64751], [35.48116, 50.66405], [35.47704, 50.77274], [35.41367, 50.80227], [35.39307, 50.92145], [35.32598, 50.94524], [35.40837, 51.04119], [35.31774, 51.08434], [35.20375, 51.04723], [35.12685, 51.16191], [35.14058, 51.23162], [34.97304, 51.2342], [34.82472, 51.17483], [34.6874, 51.18], [34.6613, 51.25053], [34.38802, 51.2746], [34.31661, 51.23936], [34.23009, 51.26429], [34.33446, 51.363], [34.22048, 51.4187], [34.30562, 51.5205], [34.17599, 51.63253], [34.07765, 51.67065], [34.42922, 51.72852], [34.41136, 51.82793], [34.09413, 52.00835], [34.11199, 52.14087], [34.05239, 52.20132], [33.78789, 52.37204], [33.55718, 52.30324], [33.48027, 52.31499], [33.51323, 52.35779], [33.18913, 52.3754], [32.89937, 52.2461], [32.85405, 52.27888], [32.69475, 52.25535], [32.54781, 52.32423], [32.3528, 52.32842], [32.38988, 52.24946], [32.33083, 52.23685], [32.34044, 52.1434], [32.2777, 52.10266], [32.23331, 52.08085], [32.08813, 52.03319], [31.92159, 52.05144], [31.96141, 52.08015], [31.85018, 52.11305], [31.81722, 52.09955], [31.7822, 52.11406], [31.38326, 52.12991], [31.25142, 52.04131], [31.13332, 52.1004], [30.95589, 52.07775], [30.90897, 52.00699], [30.76443, 51.89739], [30.68804, 51.82806], [30.51946, 51.59649], [30.64992, 51.35014], [30.56203, 51.25655], [30.36153, 51.33984], [30.34642, 51.42555], [30.17888, 51.51025], [29.77376, 51.4461], [29.7408, 51.53417], [29.54372, 51.48372], [29.49773, 51.39814], [29.42357, 51.4187], [29.32881, 51.37843], [29.25191, 51.49828], [29.25603, 51.57089], [29.20659, 51.56918], [29.16402, 51.64679], [29.1187, 51.65872], [28.99098, 51.56833], [28.95528, 51.59222], [28.81795, 51.55552], [28.76027, 51.48802], [28.78224, 51.45294], [28.75615, 51.41442], [28.73143, 51.46236], [28.69161, 51.44695], [28.64429, 51.5664], [28.47051, 51.59734], [28.37592, 51.54505], [28.23452, 51.66988], [28.10658, 51.57857], [27.95827, 51.56065], [27.91844, 51.61952], [27.85253, 51.62293], [27.76052, 51.47604], [27.67125, 51.50854], [27.71932, 51.60672], [27.55727, 51.63486], [27.51058, 51.5854], [27.47212, 51.61184], [27.24828, 51.60161], [27.26613, 51.65957], [27.20948, 51.66713], [27.20602, 51.77291], [26.99422, 51.76933], [26.9489, 51.73788], [26.80043, 51.75777], [26.69759, 51.82284], [26.46962, 51.80501], [26.39367, 51.87315], [26.19084, 51.86781], [26.00408, 51.92967], [25.83217, 51.92587], [25.80574, 51.94556], [25.73673, 51.91973], [25.46163, 51.92205], [25.20228, 51.97143], [24.98784, 51.91273], [24.37123, 51.88222], [24.29021, 51.80841], [24.3163, 51.75063], [24.13075, 51.66979], [23.99907, 51.58369], [23.8741, 51.59734], [23.91118, 51.63316], [23.7766, 51.66809], [23.60906, 51.62122], [23.6736, 51.50255], [23.62751, 51.50512], [23.69905, 51.40871], [23.63858, 51.32182], [23.80678, 51.18405], [23.90376, 51.07697], [23.92217, 51.00836], [24.04576, 50.90196], [24.14524, 50.86128], [24.0952, 50.83262], [23.99254, 50.83847], [23.95925, 50.79271], [24.0595, 50.71625], [24.0996, 50.60752], [24.07048, 50.5071], [24.03668, 50.44507], [23.99563, 50.41289], [23.79445, 50.40481], [23.71382, 50.38248], [23.67635, 50.33385], [23.28221, 50.0957], [22.99329, 49.84249], [22.83179, 49.69875], [22.80261, 49.69098], [22.78304, 49.65543], [22.64534, 49.53094], [22.69444, 49.49378], [22.748, 49.32759], [22.72009, 49.20288], [22.86336, 49.10513], [22.89122, 49.00725], [22.56155, 49.08865], [22.54338, 49.01424], [22.48296, 48.99172], [22.42934, 48.92857], [22.34151, 48.68893], [22.21379, 48.6218], [22.16023, 48.56548], [22.14689, 48.4005], [22.2083, 48.42534], [22.38133, 48.23726], [22.49806, 48.25189], [22.59007, 48.15121], [22.58733, 48.10813], [22.66835, 48.09162], [22.73427, 48.12005], [22.81804, 48.11363], [22.87847, 48.04665], [22.84276, 47.98602], [22.89849, 47.95851], [22.94301, 47.96672], [22.92241, 48.02002], [23.0158, 47.99338], [23.08858, 48.00716], [23.1133, 48.08061], [23.15999, 48.12188], [23.27397, 48.08245], [23.33577, 48.0237], [23.4979, 47.96858], [23.52803, 48.01818], [23.5653, 48.00499], [23.63894, 48.00293], [23.66262, 47.98786], [23.75188, 47.99705], [23.80904, 47.98142], [23.8602, 47.9329], [23.89352, 47.94512], [23.94192, 47.94868], [23.96337, 47.96672], [23.98553, 47.96076], [24.00801, 47.968], [24.02999, 47.95087], [24.06466, 47.95317], [24.11281, 47.91487], [24.22566, 47.90231], [24.34926, 47.9244], [24.43578, 47.97131], [24.61994, 47.95062], [24.70632, 47.84428], [24.81893, 47.82031], [24.88896, 47.7234], [25.11144, 47.75203], [25.23778, 47.89403], [25.63878, 47.94924], [25.77723, 47.93919], [26.05901, 47.9897], [26.17711, 47.99246], [26.33504, 48.18418], [26.55202, 48.22445], [26.62823, 48.25804], [26.6839, 48.35828], [26.79239, 48.29071], [26.82809, 48.31629], [26.71274, 48.40388], [26.85556, 48.41095], [26.93384, 48.36558], [27.03821, 48.37653], [27.0231, 48.42485], [27.08078, 48.43214], [27.13434, 48.37288], [27.27855, 48.37534], [27.32159, 48.4434], [27.37604, 48.44398], [27.37741, 48.41026], [27.44333, 48.41209], [27.46942, 48.454], [27.5889, 48.49224], [27.59027, 48.46311], [27.6658, 48.44034], [27.74422, 48.45926], [27.79225, 48.44244], [27.81902, 48.41874], [27.87533, 48.4037], [27.88391, 48.36699], [27.95883, 48.32368], [28.04527, 48.32661], [28.09873, 48.3124], [28.07504, 48.23494], [28.17666, 48.25963], [28.19314, 48.20749], [28.2856, 48.23202], [28.32508, 48.23384], [28.35519, 48.24957], [28.36996, 48.20543], [28.34912, 48.1787], [28.30586, 48.1597], [28.30609, 48.14018], [28.34009, 48.13147], [28.38712, 48.17567], [28.43701, 48.15832], [28.42454, 48.12047], [28.48428, 48.0737], [28.53921, 48.17453], [28.69896, 48.13106], [28.85232, 48.12506], [28.8414, 48.03392], [28.9306, 47.96255], [29.1723, 47.99013], [29.19839, 47.89261], [29.27804, 47.88893], [29.20663, 47.80367], [29.27255, 47.79953], [29.22242, 47.73607], [29.22414, 47.60012], [29.11743, 47.55001], [29.18603, 47.43387], [29.3261, 47.44664], [29.39889, 47.30179], [29.47854, 47.30366], [29.48678, 47.36043], [29.5733, 47.36508], [29.59665, 47.25521], [29.54996, 47.24962], [29.57696, 47.13581], [29.49732, 47.12878], [29.53044, 47.07851], [29.61038, 47.09932], [29.62137, 47.05069], [29.57056, 46.94766], [29.72986, 46.92234], [29.75458, 46.8604], [29.87405, 46.88199], [29.98814, 46.82358], [29.94522, 46.80055], [29.9743, 46.75325], [29.94409, 46.56002], [29.88916, 46.54302], [30.02511, 46.45132], [30.16794, 46.40967], [30.09103, 46.38694], [29.94114, 46.40114], [29.88329, 46.35851], [29.74496, 46.45605], [29.66359, 46.4215], [29.6763, 46.36041], [29.5939, 46.35472], [29.49914, 46.45889], [29.35357, 46.49505], [29.24886, 46.37912], [29.23547, 46.55435], [29.02409, 46.49582], [29.01241, 46.46177], [28.9306, 46.45699], [29.004, 46.31495], [28.98478, 46.31803], [28.94953, 46.25852], [29.06656, 46.19716], [28.94643, 46.09176], [29.00613, 46.04962], [28.98004, 46.00385], [28.74383, 45.96664], [28.78503, 45.83475], [28.69852, 45.81753], [28.70401, 45.78019], [28.52823, 45.73803], [28.47879, 45.66994], [28.51587, 45.6613], [28.54196, 45.58062], [28.49252, 45.56716], [28.51449, 45.49982], [28.43072, 45.48538], [28.41836, 45.51715], [28.30201, 45.54744], [28.21139, 45.46895], [28.28504, 45.43907], [28.34554, 45.32102], [28.5735, 45.24759], [28.71358, 45.22631], [28.78911, 45.24179], [28.81383, 45.3384], [28.94292, 45.28045], [28.96077, 45.33164], [29.24779, 45.43388], [29.42632, 45.44545], [29.59798, 45.38857], [29.68175, 45.26885], [29.65428, 45.25629], [29.69272, 45.19227], [30.04414, 45.08461], [31.62627, 45.50633], [33.54017, 46.0123], [33.59087, 46.06013], [33.57318, 46.10317]]]] } },
     { type: "Feature", properties: { iso1A2: "UG", iso1A3: "UGA", iso1N3: "800", wikidata: "Q1036", nameEn: "Uganda", groups: ["014", "202", "002", "UN"], driveSide: "left", callingCodes: ["256"] }, geometry: { type: "MultiPolygon", coordinates: [[[[33.93107, -0.99298], [33.9264, -0.54188], [33.98449, -0.13079], [33.90936, 0.10581], [34.10067, 0.36372], [34.08727, 0.44713], [34.11408, 0.48884], [34.13493, 0.58118], [34.20196, 0.62289], [34.27345, 0.63182], [34.31516, 0.75693], [34.40041, 0.80266], [34.43349, 0.85254], [34.52369, 1.10692], [34.57427, 1.09868], [34.58029, 1.14712], [34.67562, 1.21265], [34.80223, 1.22754], [34.82606, 1.26626], [34.82606, 1.30944], [34.7918, 1.36752], [34.87819, 1.5596], [34.92734, 1.56109], [34.9899, 1.6668], [34.98692, 1.97348], [34.90947, 2.42447], [34.95267, 2.47209], [34.77244, 2.70272], [34.78137, 2.76223], [34.73967, 2.85447], [34.65774, 2.8753], [34.60114, 2.93034], [34.56242, 3.11478], [34.45815, 3.18319], [34.40006, 3.37949], [34.41794, 3.44342], [34.39112, 3.48802], [34.44922, 3.51627], [34.45815, 3.67385], [34.15429, 3.80464], [34.06046, 4.15235], [33.9873, 4.23316], [33.51264, 3.75068], [33.18356, 3.77812], [33.02852, 3.89296], [32.89746, 3.81339], [32.72021, 3.77327], [32.41337, 3.748], [32.20782, 3.6053], [32.19888, 3.50867], [32.08866, 3.53543], [32.08491, 3.56287], [32.05187, 3.589], [31.95907, 3.57408], [31.96205, 3.6499], [31.86821, 3.78664], [31.81459, 3.82083], [31.72075, 3.74354], [31.50776, 3.63652], [31.50478, 3.67814], [31.29476, 3.8015], [31.16666, 3.79853], [30.97601, 3.693], [30.85153, 3.48867], [30.94081, 3.50847], [30.93486, 3.40737], [30.84251, 3.26908], [30.77101, 3.04897], [30.8574, 2.9508], [30.8857, 2.83923], [30.75612, 2.5863], [30.74271, 2.43601], [30.83059, 2.42559], [30.91102, 2.33332], [30.96911, 2.41071], [31.06593, 2.35862], [31.07934, 2.30207], [31.12104, 2.27676], [31.1985, 2.29462], [31.20148, 2.2217], [31.28042, 2.17853], [31.30127, 2.11006], [30.48503, 1.21675], [30.24671, 1.14974], [30.22139, 0.99635], [30.1484, 0.89805], [29.98307, 0.84295], [29.95477, 0.64486], [29.97413, 0.52124], [29.87284, 0.39166], [29.81922, 0.16824], [29.77454, 0.16675], [29.7224, 0.07291], [29.72687, -0.08051], [29.65091, -0.46777], [29.67474, -0.47969], [29.67176, -0.55714], [29.62708, -0.71055], [29.63006, -0.8997], [29.58388, -0.89821], [29.59061, -1.39016], [29.82657, -1.31187], [29.912, -1.48269], [30.16369, -1.34303], [30.35212, -1.06896], [30.47194, -1.0555], [30.64166, -1.06601], [30.70631, -1.01175], [30.76635, -0.9852], [30.80408, -0.99911], [33.93107, -0.99298]]]] } },
     { 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 = {};
+  var _whichPolygon = {};
+  var _featuresByCode = {};
   var idFilterRegex = /(?=(?!^(and|the|of|el|la|de)$))(\b(and|the|of|el|la|de)\b)|[-_ .,'()&[\]/]/gi;
   function canonicalID(id2) {
-    const s = id2 || "";
-    if (s.charAt(0) === ".") {
-      return s.toUpperCase();
+    const s2 = id2 || "";
+    if (s2.charAt(0) === ".") {
+      return s2.toUpperCase();
     } else {
-      return s.replace(idFilterRegex, "").toUpperCase();
+      return s2.replace(idFilterRegex, "").toUpperCase();
     }
   }
   var levels = [
   function loadDerivedDataAndCaches(borders2) {
     const identifierProps = ["iso1A2", "iso1A3", "m49", "wikidata", "emojiFlag", "ccTLD", "nameEn"];
     let geometryFeatures = [];
-    borders2.features.forEach((feature22) => {
-      feature22.properties.id = feature22.properties.iso1A2 || feature22.properties.m49 || feature22.properties.wikidata;
+    for (const feature22 of borders2.features) {
+      const props = feature22.properties;
+      props.id = props.iso1A2 || props.m49 || props.wikidata;
       loadM49(feature22);
       loadTLD(feature22);
       loadIsoStatus(feature22);
       loadGroups(feature22);
       loadFlag(feature22);
       cacheFeatureByIDs(feature22);
-      if (feature22.geometry)
+      if (feature22.geometry) {
         geometryFeatures.push(feature22);
-    });
-    borders2.features.forEach((feature22) => {
+      }
+    }
+    for (const feature22 of borders2.features) {
       feature22.properties.groups = feature22.properties.groups.map((groupID) => {
-        return featuresByCode[groupID].properties.id;
+        return _featuresByCode[groupID].properties.id;
       });
       loadMembersForGroupsOf(feature22);
-    });
-    borders2.features.forEach((feature22) => {
+    }
+    for (const feature22 of borders2.features) {
       loadRoadSpeedUnit(feature22);
       loadRoadHeightUnit(feature22);
       loadDriveSide(feature22);
       loadCallingCodes(feature22);
       loadGroupGroups(feature22);
-    });
-    borders2.features.forEach((feature22) => {
+    }
+    for (const feature22 of borders2.features) {
       feature22.properties.groups.sort((groupID1, groupID2) => {
-        return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
+        return levels.indexOf(_featuresByCode[groupID1].properties.level) - levels.indexOf(_featuresByCode[groupID2].properties.level);
       });
-      if (feature22.properties.members)
+      if (feature22.properties.members) {
         feature22.properties.members.sort((id1, id2) => {
-          const diff = levels.indexOf(featuresByCode[id1].properties.level) - levels.indexOf(featuresByCode[id2].properties.level);
+          const diff = levels.indexOf(_featuresByCode[id1].properties.level) - levels.indexOf(_featuresByCode[id2].properties.level);
           if (diff === 0) {
-            return borders2.features.indexOf(featuresByCode[id1]) - borders2.features.indexOf(featuresByCode[id2]);
+            return borders2.features.indexOf(_featuresByCode[id1]) - borders2.features.indexOf(_featuresByCode[id2]);
           }
           return diff;
         });
-    });
+      }
+    }
     const geometryOnlyCollection = {
       type: "FeatureCollection",
       features: geometryFeatures
     };
-    whichPolygonGetter = (0, import_which_polygon.default)(geometryOnlyCollection);
+    _whichPolygon = (0, import_which_polygon.default)(geometryOnlyCollection);
     function loadGroups(feature22) {
       const props = feature22.properties;
       if (!props.groups) {
     }
     function loadTLD(feature22) {
       const props = feature22.properties;
-      if (props.level === "unitedNations")
-        return;
+      if (props.level === "unitedNations") return;
+      if (props.ccTLD === null) return;
       if (!props.ccTLD && props.iso1A2) {
         props.ccTLD = "." + props.iso1A2.toLowerCase();
       }
     }
     function loadLevel(feature22) {
       const props = feature22.properties;
-      if (props.level)
-        return;
+      if (props.level) return;
       if (!props.country) {
         props.level = "country";
       } else if (!props.iso1A2 || props.isoStatus === "official") {
     }
     function loadGroupGroups(feature22) {
       const props = feature22.properties;
-      if (feature22.geometry || !props.members)
-        return;
+      if (feature22.geometry || !props.members) return;
       const featureLevelIndex = levels.indexOf(props.level);
       let sharedGroups = [];
       props.members.forEach((memberID, index) => {
-        const member = featuresByCode[memberID];
+        const member = _featuresByCode[memberID];
         const memberGroups = member.properties.groups.filter((groupID) => {
-          return groupID !== feature22.properties.id && featureLevelIndex < levels.indexOf(featuresByCode[groupID].properties.level);
+          return groupID !== feature22.properties.id && featureLevelIndex < levels.indexOf(_featuresByCode[groupID].properties.level);
         });
         if (index === 0) {
           sharedGroups = memberGroups;
           sharedGroups = sharedGroups.filter((groupID) => memberGroups.indexOf(groupID) !== -1);
         }
       });
-      props.groups = props.groups.concat(sharedGroups.filter((groupID) => props.groups.indexOf(groupID) === -1));
-      sharedGroups.forEach((groupID) => {
-        const groupFeature = featuresByCode[groupID];
+      props.groups = props.groups.concat(
+        sharedGroups.filter((groupID) => props.groups.indexOf(groupID) === -1)
+      );
+      for (const groupID of sharedGroups) {
+        const groupFeature = _featuresByCode[groupID];
         if (groupFeature.properties.members.indexOf(props.id) === -1) {
           groupFeature.properties.members.push(props.id);
         }
-      });
+      }
     }
     function loadRoadSpeedUnit(feature22) {
       const props = feature22.properties;
       if (feature22.geometry) {
-        if (!props.roadSpeedUnit)
-          props.roadSpeedUnit = "km/h";
+        if (!props.roadSpeedUnit) props.roadSpeedUnit = "km/h";
       } else if (props.members) {
-        const vals = Array.from(new Set(props.members.map((id2) => {
-          const member = featuresByCode[id2];
-          if (member.geometry)
-            return member.properties.roadSpeedUnit || "km/h";
-        }).filter(Boolean)));
-        if (vals.length === 1)
-          props.roadSpeedUnit = vals[0];
+        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];
       }
     }
     function loadRoadHeightUnit(feature22) {
       const props = feature22.properties;
       if (feature22.geometry) {
-        if (!props.roadHeightUnit)
-          props.roadHeightUnit = "m";
+        if (!props.roadHeightUnit) props.roadHeightUnit = "m";
       } else if (props.members) {
-        const vals = Array.from(new Set(props.members.map((id2) => {
-          const member = featuresByCode[id2];
-          if (member.geometry)
-            return member.properties.roadHeightUnit || "m";
-        }).filter(Boolean)));
-        if (vals.length === 1)
-          props.roadHeightUnit = vals[0];
+        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];
       }
     }
     function loadDriveSide(feature22) {
       const props = feature22.properties;
       if (feature22.geometry) {
-        if (!props.driveSide)
-          props.driveSide = "right";
+        if (!props.driveSide) props.driveSide = "right";
       } else if (props.members) {
-        const vals = Array.from(new Set(props.members.map((id2) => {
-          const member = featuresByCode[id2];
-          if (member.geometry)
-            return member.properties.driveSide || "right";
-        }).filter(Boolean)));
-        if (vals.length === 1)
-          props.driveSide = vals[0];
+        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) {
-      if (!feature22.properties.iso1A2)
-        return;
+      if (!feature22.properties.iso1A2) return;
       const flag = feature22.properties.iso1A2.replace(/./g, function(char) {
         return String.fromCodePoint(char.charCodeAt(0) + 127397);
       });
       feature22.properties.emojiFlag = flag;
     }
     function loadMembersForGroupsOf(feature22) {
-      feature22.properties.groups.forEach((groupID) => {
-        const groupFeature = featuresByCode[groupID];
+      for (const groupID of feature22.properties.groups) {
+        const groupFeature = _featuresByCode[groupID];
         if (!groupFeature.properties.members) {
           groupFeature.properties.members = [];
         }
         groupFeature.properties.members.push(feature22.properties.id);
-      });
+      }
     }
     function cacheFeatureByIDs(feature22) {
       let ids = [];
-      identifierProps.forEach((prop) => {
+      for (const prop of identifierProps) {
         const id2 = feature22.properties[prop];
-        if (id2)
+        if (id2) {
           ids.push(id2);
-      });
-      (feature22.properties.aliases || []).forEach((alias) => {
+        }
+      }
+      for (const alias of feature22.properties.aliases || []) {
         ids.push(alias);
-      });
-      ids.forEach((id2) => {
-        let cid = canonicalID(id2);
-        featuresByCode[cid] = feature22;
-      });
+      }
+      for (const id2 of ids) {
+        const cid = canonicalID(id2);
+        _featuresByCode[cid] = feature22;
+      }
     }
   }
   function locArray(loc) {
   }
   function smallestFeature(loc) {
     const query = locArray(loc);
-    const featureProperties = whichPolygonGetter(query);
-    if (!featureProperties)
-      return null;
-    return featuresByCode[featureProperties.id];
+    const featureProperties = _whichPolygon(query);
+    if (!featureProperties) return null;
+    return _featuresByCode[featureProperties.id];
   }
   function countryFeature(loc) {
     const feature22 = smallestFeature(loc);
-    if (!feature22)
-      return null;
+    if (!feature22) return null;
     const countryCode = feature22.properties.country || feature22.properties.iso1A2;
-    return featuresByCode[countryCode] || null;
+    return _featuresByCode[countryCode] || null;
   }
   var defaultOpts = {
     level: void 0,
     const maxLevel = opts.maxLevel || "world";
     const withProp = opts.withProp;
     const targetLevelIndex = levels.indexOf(targetLevel);
-    if (targetLevelIndex === -1)
-      return null;
+    if (targetLevelIndex === -1) return null;
     const maxLevelIndex = levels.indexOf(maxLevel);
-    if (maxLevelIndex === -1)
-      return null;
-    if (maxLevelIndex < targetLevelIndex)
-      return null;
+    if (maxLevelIndex === -1) return null;
+    if (maxLevelIndex < targetLevelIndex) return null;
     if (targetLevel === "country") {
       const fastFeature = countryFeature(loc);
       if (fastFeature) {
         }
       }
     }
-    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;
         }
     } else {
       stringID = canonicalID(id2);
     }
-    return featuresByCode[stringID] || null;
+    return _featuresByCode[stringID] || null;
   }
-  function smallestFeaturesForBbox(bbox) {
-    return whichPolygonGetter.bbox(bbox).map((props) => featuresByCode[props.id]);
+  function smallestFeaturesForBbox(bbox2) {
+    return _whichPolygon.bbox(bbox2).map((props) => _featuresByCode[props.id]);
   }
   function smallestOrMatchingFeature(query) {
     if (typeof query === "object") {
   function iso1A2Code(query, opts = defaultOpts) {
     opts.withProp = "iso1A2";
     const match = feature(query, opts);
-    if (!match)
-      return null;
+    if (!match) return null;
     return match.properties.iso1A2 || null;
   }
+  function propertiesForQuery(query, property) {
+    const features = featuresContaining(query, false);
+    return features.map((feature22) => feature22.properties[property]).filter(Boolean);
+  }
+  function iso1A2Codes(query) {
+    return propertiesForQuery(query, "iso1A2");
+  }
   function featuresContaining(query, strict) {
     let matchingFeatures;
     if (Array.isArray(query) && query.length === 4) {
       const smallestOrMatching = smallestOrMatchingFeature(query);
       matchingFeatures = smallestOrMatching ? [smallestOrMatching] : [];
     }
-    if (!matchingFeatures.length)
-      return [];
+    if (!matchingFeatures.length) return [];
     let returnFeatures;
     if (!strict || typeof query === "object") {
       returnFeatures = matchingFeatures.slice();
     } else {
       returnFeatures = [];
     }
-    matchingFeatures.forEach((feature22) => {
+    for (const feature22 of matchingFeatures) {
       const properties = feature22.properties;
-      properties.groups.forEach((groupID) => {
-        const groupFeature = featuresByCode[groupID];
+      for (const groupID of properties.groups) {
+        const groupFeature = _featuresByCode[groupID];
         if (returnFeatures.indexOf(groupFeature) === -1) {
           returnFeatures.push(groupFeature);
         }
-      });
-    });
+      }
+    }
     return returnFeatures;
   }
   function featuresIn(id2, strict) {
     const feature22 = featureForID(id2);
-    if (!feature22)
-      return [];
-    let features2 = [];
+    if (!feature22) return [];
+    let features = [];
     if (!strict) {
-      features2.push(feature22);
+      features.push(feature22);
     }
     const properties = feature22.properties;
-    (properties.members || []).forEach((memberID) => {
-      features2.push(featuresByCode[memberID]);
-    });
-    return features2;
+    for (const memberID of properties.members || []) {
+      features.push(_featuresByCode[memberID]);
+    }
+    return features;
   }
   function aggregateFeature(id2) {
-    const features2 = featuresIn(id2, false);
-    if (features2.length === 0)
-      return null;
+    var _a3;
+    const features = featuresIn(id2, false);
+    if (features.length === 0) return null;
     let aggregateCoordinates = [];
-    features2.forEach((feature22) => {
-      if (feature22.geometry && feature22.geometry.type === "MultiPolygon" && feature22.geometry.coordinates) {
+    for (const feature22 of features) {
+      if (((_a3 = feature22.geometry) == null ? void 0 : _a3.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
-  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) {
-      this._cache = {};
-      this._strict = true;
-      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))
+  // node_modules/polyclip-ts/dist/constant.js
+  var constant_default5 = (x2) => {
+    return () => {
+      return x2;
+    };
+  };
+
+  // node_modules/polyclip-ts/dist/compare.js
+  var compare_default = (eps) => {
+    const almostEqual = eps ? (a2, b2) => b2.minus(a2).abs().isLessThanOrEqualTo(eps) : constant_default5(false);
+    return (a2, b2) => {
+      if (almostEqual(a2, b2))
+        return 0;
+      return a2.comparedTo(b2);
+    };
+  };
+
+  // node_modules/polyclip-ts/dist/orient.js
+  function orient_default(eps) {
+    const almostCollinear = eps ? (area2, ax, ay, cx, cy) => area2.exponentiatedBy(2).isLessThanOrEqualTo(cx.minus(ax).exponentiatedBy(2).plus(cy.minus(ay).exponentiatedBy(2)).times(eps)) : constant_default5(false);
+    return (a2, b2, c2) => {
+      const ax = a2.x, ay = a2.y, cx = c2.x, cy = c2.y;
+      const area2 = ay.minus(cy).times(b2.x.minus(cx)).minus(ax.minus(cx).times(b2.y.minus(cy)));
+      if (almostCollinear(area2, ax, ay, cx, cy))
+        return 0;
+      return area2.comparedTo(0);
+    };
+  }
+
+  // node_modules/bignumber.js/bignumber.mjs
+  var isNumeric = /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
+  var mathceil = Math.ceil;
+  var mathfloor = Math.floor;
+  var bignumberError = "[BigNumber Error] ";
+  var tooManyDigits = bignumberError + "Number primitive has more than 15 significant digits: ";
+  var BASE = 1e14;
+  var LOG_BASE = 14;
+  var MAX_SAFE_INTEGER = 9007199254740991;
+  var POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13];
+  var SQRT_BASE = 1e7;
+  var MAX = 1e9;
+  function clone(configObject) {
+    var div, convertBase, parseNumeric2, P2 = BigNumber2.prototype = { constructor: BigNumber2, toString: null, valueOf: null }, ONE = new BigNumber2(1), DECIMAL_PLACES = 20, ROUNDING_MODE = 4, TO_EXP_NEG = -7, TO_EXP_POS = 21, MIN_EXP = -1e7, MAX_EXP = 1e7, CRYPTO = false, MODULO_MODE = 1, POW_PRECISION = 0, FORMAT = {
+      prefix: "",
+      groupSize: 3,
+      secondaryGroupSize: 0,
+      groupSeparator: ",",
+      decimalSeparator: ".",
+      fractionGroupSize: 0,
+      fractionGroupSeparator: "\xA0",
+      // non-breaking space
+      suffix: ""
+    }, ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz", alphabetHasNormalDecimalDigits = true;
+    function BigNumber2(v2, b2) {
+      var alphabet, c2, caseChanged, e3, i3, isNum, len, str, x2 = this;
+      if (!(x2 instanceof BigNumber2)) return new BigNumber2(v2, b2);
+      if (b2 == null) {
+        if (v2 && v2._isBigNumber === true) {
+          x2.s = v2.s;
+          if (!v2.c || v2.e > MAX_EXP) {
+            x2.c = x2.e = null;
+          } else if (v2.e < MIN_EXP) {
+            x2.c = [x2.e = 0];
+          } else {
+            x2.e = v2.e;
+            x2.c = v2.c.slice();
+          }
+          return;
+        }
+        if ((isNum = typeof v2 == "number") && v2 * 0 == 0) {
+          x2.s = 1 / v2 < 0 ? (v2 = -v2, -1) : 1;
+          if (v2 === ~~v2) {
+            for (e3 = 0, i3 = v2; i3 >= 10; i3 /= 10, e3++) ;
+            if (e3 > MAX_EXP) {
+              x2.c = x2.e = null;
+            } else {
+              x2.e = e3;
+              x2.c = [v2];
+            }
             return;
-          id2 = id2.toLowerCase();
-          feature3.id = id2;
-          props.id = id2;
-          if (!props.area) {
-            const area = import_geojson_area.default.geometry(feature3.geometry) / 1e6;
-            props.area = Number(area.toFixed(2));
           }
-          this._cache[id2] = feature3;
-        });
+          str = String(v2);
+        } else {
+          if (!isNumeric.test(str = String(v2))) return parseNumeric2(x2, str, isNum);
+          x2.s = str.charCodeAt(0) == 45 ? (str = str.slice(1), -1) : 1;
+        }
+        if ((e3 = str.indexOf(".")) > -1) str = str.replace(".", "");
+        if ((i3 = str.search(/e/i)) > 0) {
+          if (e3 < 0) e3 = i3;
+          e3 += +str.slice(i3 + 1);
+          str = str.substring(0, i3);
+        } else if (e3 < 0) {
+          e3 = str.length;
+        }
+      } else {
+        intCheck(b2, 2, ALPHABET.length, "Base");
+        if (b2 == 10 && alphabetHasNormalDecimalDigits) {
+          x2 = new BigNumber2(v2);
+          return round(x2, DECIMAL_PLACES + x2.e + 1, ROUNDING_MODE);
+        }
+        str = String(v2);
+        if (isNum = typeof v2 == "number") {
+          if (v2 * 0 != 0) return parseNumeric2(x2, str, isNum, b2);
+          x2.s = 1 / v2 < 0 ? (str = str.slice(1), -1) : 1;
+          if (BigNumber2.DEBUG && str.replace(/^0\.0*|\./, "").length > 15) {
+            throw Error(tooManyDigits + v2);
+          }
+        } else {
+          x2.s = str.charCodeAt(0) === 45 ? (str = str.slice(1), -1) : 1;
+        }
+        alphabet = ALPHABET.slice(0, b2);
+        e3 = i3 = 0;
+        for (len = str.length; i3 < len; i3++) {
+          if (alphabet.indexOf(c2 = str.charAt(i3)) < 0) {
+            if (c2 == ".") {
+              if (i3 > e3) {
+                e3 = len;
+                continue;
+              }
+            } else if (!caseChanged) {
+              if (str == str.toUpperCase() && (str = str.toLowerCase()) || str == str.toLowerCase() && (str = str.toUpperCase())) {
+                caseChanged = true;
+                i3 = -1;
+                e3 = 0;
+                continue;
+              }
+            }
+            return parseNumeric2(x2, String(v2), isNum, b2);
+          }
+        }
+        isNum = false;
+        str = convertBase(str, b2, 10, x2.s);
+        if ((e3 = str.indexOf(".")) > -1) str = str.replace(".", "");
+        else e3 = str.length;
       }
-      let world = _cloneDeep(feature("Q2"));
-      world.geometry = {
-        type: "Polygon",
-        coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
+      for (i3 = 0; str.charCodeAt(i3) === 48; i3++) ;
+      for (len = str.length; str.charCodeAt(--len) === 48; ) ;
+      if (str = str.slice(i3, ++len)) {
+        len -= i3;
+        if (isNum && BigNumber2.DEBUG && len > 15 && (v2 > MAX_SAFE_INTEGER || v2 !== mathfloor(v2))) {
+          throw Error(tooManyDigits + x2.s * v2);
+        }
+        if ((e3 = e3 - i3 - 1) > MAX_EXP) {
+          x2.c = x2.e = null;
+        } else if (e3 < MIN_EXP) {
+          x2.c = [x2.e = 0];
+        } else {
+          x2.e = e3;
+          x2.c = [];
+          i3 = (e3 + 1) % LOG_BASE;
+          if (e3 < 0) i3 += LOG_BASE;
+          if (i3 < len) {
+            if (i3) x2.c.push(+str.slice(0, i3));
+            for (len -= LOG_BASE; i3 < len; ) {
+              x2.c.push(+str.slice(i3, i3 += LOG_BASE));
+            }
+            i3 = LOG_BASE - (str = str.slice(i3)).length;
+          } else {
+            i3 -= len;
+          }
+          for (; i3--; str += "0") ;
+          x2.c.push(+str);
+        }
+      } else {
+        x2.c = [x2.e = 0];
+      }
+    }
+    BigNumber2.clone = clone;
+    BigNumber2.ROUND_UP = 0;
+    BigNumber2.ROUND_DOWN = 1;
+    BigNumber2.ROUND_CEIL = 2;
+    BigNumber2.ROUND_FLOOR = 3;
+    BigNumber2.ROUND_HALF_UP = 4;
+    BigNumber2.ROUND_HALF_DOWN = 5;
+    BigNumber2.ROUND_HALF_EVEN = 6;
+    BigNumber2.ROUND_HALF_CEIL = 7;
+    BigNumber2.ROUND_HALF_FLOOR = 8;
+    BigNumber2.EUCLID = 9;
+    BigNumber2.config = BigNumber2.set = function(obj) {
+      var p2, v2;
+      if (obj != null) {
+        if (typeof obj == "object") {
+          if (obj.hasOwnProperty(p2 = "DECIMAL_PLACES")) {
+            v2 = obj[p2];
+            intCheck(v2, 0, MAX, p2);
+            DECIMAL_PLACES = v2;
+          }
+          if (obj.hasOwnProperty(p2 = "ROUNDING_MODE")) {
+            v2 = obj[p2];
+            intCheck(v2, 0, 8, p2);
+            ROUNDING_MODE = v2;
+          }
+          if (obj.hasOwnProperty(p2 = "EXPONENTIAL_AT")) {
+            v2 = obj[p2];
+            if (v2 && v2.pop) {
+              intCheck(v2[0], -MAX, 0, p2);
+              intCheck(v2[1], 0, MAX, p2);
+              TO_EXP_NEG = v2[0];
+              TO_EXP_POS = v2[1];
+            } else {
+              intCheck(v2, -MAX, MAX, p2);
+              TO_EXP_NEG = -(TO_EXP_POS = v2 < 0 ? -v2 : v2);
+            }
+          }
+          if (obj.hasOwnProperty(p2 = "RANGE")) {
+            v2 = obj[p2];
+            if (v2 && v2.pop) {
+              intCheck(v2[0], -MAX, -1, p2);
+              intCheck(v2[1], 1, MAX, p2);
+              MIN_EXP = v2[0];
+              MAX_EXP = v2[1];
+            } else {
+              intCheck(v2, -MAX, MAX, p2);
+              if (v2) {
+                MIN_EXP = -(MAX_EXP = v2 < 0 ? -v2 : v2);
+              } else {
+                throw Error(bignumberError + p2 + " cannot be zero: " + v2);
+              }
+            }
+          }
+          if (obj.hasOwnProperty(p2 = "CRYPTO")) {
+            v2 = obj[p2];
+            if (v2 === !!v2) {
+              if (v2) {
+                if (typeof crypto != "undefined" && crypto && (crypto.getRandomValues || crypto.randomBytes)) {
+                  CRYPTO = v2;
+                } else {
+                  CRYPTO = !v2;
+                  throw Error(bignumberError + "crypto unavailable");
+                }
+              } else {
+                CRYPTO = v2;
+              }
+            } else {
+              throw Error(bignumberError + p2 + " not true or false: " + v2);
+            }
+          }
+          if (obj.hasOwnProperty(p2 = "MODULO_MODE")) {
+            v2 = obj[p2];
+            intCheck(v2, 0, 9, p2);
+            MODULO_MODE = v2;
+          }
+          if (obj.hasOwnProperty(p2 = "POW_PRECISION")) {
+            v2 = obj[p2];
+            intCheck(v2, 0, MAX, p2);
+            POW_PRECISION = v2;
+          }
+          if (obj.hasOwnProperty(p2 = "FORMAT")) {
+            v2 = obj[p2];
+            if (typeof v2 == "object") FORMAT = v2;
+            else throw Error(bignumberError + p2 + " not an object: " + v2);
+          }
+          if (obj.hasOwnProperty(p2 = "ALPHABET")) {
+            v2 = obj[p2];
+            if (typeof v2 == "string" && !/^.?$|[+\-.\s]|(.).*\1/.test(v2)) {
+              alphabetHasNormalDecimalDigits = v2.slice(0, 10) == "0123456789";
+              ALPHABET = v2;
+            } else {
+              throw Error(bignumberError + p2 + " invalid: " + v2);
+            }
+          }
+        } else {
+          throw Error(bignumberError + "Object expected: " + obj);
+        }
+      }
+      return {
+        DECIMAL_PLACES,
+        ROUNDING_MODE,
+        EXPONENTIAL_AT: [TO_EXP_NEG, TO_EXP_POS],
+        RANGE: [MIN_EXP, MAX_EXP],
+        CRYPTO,
+        MODULO_MODE,
+        POW_PRECISION,
+        FORMAT,
+        ALPHABET
       };
-      world.id = "Q2";
-      world.properties.id = "Q2";
-      world.properties.area = import_geojson_area.default.geometry(world.geometry) / 1e6;
-      this._cache.Q2 = world;
-    }
-    validateLocation(location) {
-      if (Array.isArray(location) && (location.length === 2 || location.length === 3)) {
-        const lon = location[0];
-        const lat = location[1];
-        const radius = location[2];
-        if (Number.isFinite(lon) && lon >= -180 && lon <= 180 && Number.isFinite(lat) && lat >= -90 && lat <= 90 && (location.length === 2 || Number.isFinite(radius) && radius > 0)) {
-          const id2 = "[" + location.toString() + "]";
-          return { type: "point", location, id: id2 };
+    };
+    BigNumber2.isBigNumber = function(v2) {
+      if (!v2 || v2._isBigNumber !== true) return false;
+      if (!BigNumber2.DEBUG) return true;
+      var i3, n3, c2 = v2.c, e3 = v2.e, s2 = v2.s;
+      out: if ({}.toString.call(c2) == "[object Array]") {
+        if ((s2 === 1 || s2 === -1) && e3 >= -MAX && e3 <= MAX && e3 === mathfloor(e3)) {
+          if (c2[0] === 0) {
+            if (e3 === 0 && c2.length === 1) return true;
+            break out;
+          }
+          i3 = (e3 + 1) % LOG_BASE;
+          if (i3 < 1) i3 += LOG_BASE;
+          if (String(c2[0]).length == i3) {
+            for (i3 = 0; i3 < c2.length; i3++) {
+              n3 = c2[i3];
+              if (n3 < 0 || n3 >= BASE || n3 !== mathfloor(n3)) break out;
+            }
+            if (n3 !== 0) return true;
+          }
         }
-      } else if (typeof location === "string" && /^\S+\.geojson$/i.test(location)) {
-        const id2 = location.toLowerCase();
-        if (this._cache[id2]) {
-          return { type: "geojson", location, id: id2 };
+      } else if (c2 === null && e3 === null && (s2 === null || s2 === 1 || s2 === -1)) {
+        return true;
+      }
+      throw Error(bignumberError + "Invalid BigNumber: " + v2);
+    };
+    BigNumber2.maximum = BigNumber2.max = function() {
+      return maxOrMin(arguments, -1);
+    };
+    BigNumber2.minimum = BigNumber2.min = function() {
+      return maxOrMin(arguments, 1);
+    };
+    BigNumber2.random = function() {
+      var pow2_53 = 9007199254740992;
+      var random53bitInt = Math.random() * pow2_53 & 2097151 ? function() {
+        return mathfloor(Math.random() * pow2_53);
+      } : function() {
+        return (Math.random() * 1073741824 | 0) * 8388608 + (Math.random() * 8388608 | 0);
+      };
+      return function(dp) {
+        var a2, b2, e3, k2, v2, i3 = 0, c2 = [], rand = new BigNumber2(ONE);
+        if (dp == null) dp = DECIMAL_PLACES;
+        else intCheck(dp, 0, MAX);
+        k2 = mathceil(dp / LOG_BASE);
+        if (CRYPTO) {
+          if (crypto.getRandomValues) {
+            a2 = crypto.getRandomValues(new Uint32Array(k2 *= 2));
+            for (; i3 < k2; ) {
+              v2 = a2[i3] * 131072 + (a2[i3 + 1] >>> 11);
+              if (v2 >= 9e15) {
+                b2 = crypto.getRandomValues(new Uint32Array(2));
+                a2[i3] = b2[0];
+                a2[i3 + 1] = b2[1];
+              } else {
+                c2.push(v2 % 1e14);
+                i3 += 2;
+              }
+            }
+            i3 = k2 / 2;
+          } else if (crypto.randomBytes) {
+            a2 = crypto.randomBytes(k2 *= 7);
+            for (; i3 < k2; ) {
+              v2 = (a2[i3] & 31) * 281474976710656 + a2[i3 + 1] * 1099511627776 + a2[i3 + 2] * 4294967296 + a2[i3 + 3] * 16777216 + (a2[i3 + 4] << 16) + (a2[i3 + 5] << 8) + a2[i3 + 6];
+              if (v2 >= 9e15) {
+                crypto.randomBytes(7).copy(a2, i3);
+              } else {
+                c2.push(v2 % 1e14);
+                i3 += 7;
+              }
+            }
+            i3 = k2 / 7;
+          } else {
+            CRYPTO = false;
+            throw Error(bignumberError + "crypto unavailable");
+          }
         }
-      } else if (typeof location === "string" || typeof location === "number") {
-        const feature3 = feature(location);
-        if (feature3) {
-          const id2 = feature3.properties.wikidata;
-          return { type: "countrycoder", location, id: id2 };
+        if (!CRYPTO) {
+          for (; i3 < k2; ) {
+            v2 = random53bitInt();
+            if (v2 < 9e15) c2[i3++] = v2 % 1e14;
+          }
+        }
+        k2 = c2[--i3];
+        dp %= LOG_BASE;
+        if (k2 && dp) {
+          v2 = POWS_TEN[LOG_BASE - dp];
+          c2[i3] = mathfloor(k2 / v2) * v2;
+        }
+        for (; c2[i3] === 0; c2.pop(), i3--) ;
+        if (i3 < 0) {
+          c2 = [e3 = 0];
+        } else {
+          for (e3 = -1; c2[0] === 0; c2.splice(0, 1), e3 -= LOG_BASE) ;
+          for (i3 = 1, v2 = c2[0]; v2 >= 10; v2 /= 10, i3++) ;
+          if (i3 < LOG_BASE) e3 -= LOG_BASE - i3;
+        }
+        rand.e = e3;
+        rand.c = c2;
+        return rand;
+      };
+    }();
+    BigNumber2.sum = function() {
+      var i3 = 1, args = arguments, sum = new BigNumber2(args[0]);
+      for (; i3 < args.length; ) sum = sum.plus(args[i3++]);
+      return sum;
+    };
+    convertBase = /* @__PURE__ */ function() {
+      var decimal = "0123456789";
+      function toBaseOut(str, baseIn, baseOut, alphabet) {
+        var j2, arr = [0], arrL, i3 = 0, len = str.length;
+        for (; i3 < len; ) {
+          for (arrL = arr.length; arrL--; arr[arrL] *= baseIn) ;
+          arr[0] += alphabet.indexOf(str.charAt(i3++));
+          for (j2 = 0; j2 < arr.length; j2++) {
+            if (arr[j2] > baseOut - 1) {
+              if (arr[j2 + 1] == null) arr[j2 + 1] = 0;
+              arr[j2 + 1] += arr[j2] / baseOut | 0;
+              arr[j2] %= baseOut;
+            }
+          }
+        }
+        return arr.reverse();
+      }
+      return function(str, baseIn, baseOut, sign2, callerIsToString) {
+        var alphabet, d2, e3, k2, r2, x2, xc, y2, i3 = str.indexOf("."), dp = DECIMAL_PLACES, rm = ROUNDING_MODE;
+        if (i3 >= 0) {
+          k2 = POW_PRECISION;
+          POW_PRECISION = 0;
+          str = str.replace(".", "");
+          y2 = new BigNumber2(baseIn);
+          x2 = y2.pow(str.length - i3);
+          POW_PRECISION = k2;
+          y2.c = toBaseOut(
+            toFixedPoint(coeffToString(x2.c), x2.e, "0"),
+            10,
+            baseOut,
+            decimal
+          );
+          y2.e = y2.c.length;
+        }
+        xc = toBaseOut(str, baseIn, baseOut, callerIsToString ? (alphabet = ALPHABET, decimal) : (alphabet = decimal, ALPHABET));
+        e3 = k2 = xc.length;
+        for (; xc[--k2] == 0; xc.pop()) ;
+        if (!xc[0]) return alphabet.charAt(0);
+        if (i3 < 0) {
+          --e3;
+        } else {
+          x2.c = xc;
+          x2.e = e3;
+          x2.s = sign2;
+          x2 = div(x2, y2, dp, rm, baseOut);
+          xc = x2.c;
+          r2 = x2.r;
+          e3 = x2.e;
+        }
+        d2 = e3 + dp + 1;
+        i3 = xc[d2];
+        k2 = baseOut / 2;
+        r2 = r2 || d2 < 0 || xc[d2 + 1] != null;
+        r2 = rm < 4 ? (i3 != null || r2) && (rm == 0 || rm == (x2.s < 0 ? 3 : 2)) : i3 > k2 || i3 == k2 && (rm == 4 || r2 || rm == 6 && xc[d2 - 1] & 1 || rm == (x2.s < 0 ? 8 : 7));
+        if (d2 < 1 || !xc[0]) {
+          str = r2 ? toFixedPoint(alphabet.charAt(1), -dp, alphabet.charAt(0)) : alphabet.charAt(0);
+        } else {
+          xc.length = d2;
+          if (r2) {
+            for (--baseOut; ++xc[--d2] > baseOut; ) {
+              xc[d2] = 0;
+              if (!d2) {
+                ++e3;
+                xc = [1].concat(xc);
+              }
+            }
+          }
+          for (k2 = xc.length; !xc[--k2]; ) ;
+          for (i3 = 0, str = ""; i3 <= k2; str += alphabet.charAt(xc[i3++])) ;
+          str = toFixedPoint(str, e3, alphabet.charAt(0));
         }
+        return str;
+      };
+    }();
+    div = /* @__PURE__ */ function() {
+      function multiply(x2, k2, base) {
+        var m2, temp, xlo, xhi, carry = 0, i3 = x2.length, klo = k2 % SQRT_BASE, khi = k2 / SQRT_BASE | 0;
+        for (x2 = x2.slice(); i3--; ) {
+          xlo = x2[i3] % SQRT_BASE;
+          xhi = x2[i3] / SQRT_BASE | 0;
+          m2 = khi * xlo + xhi * klo;
+          temp = klo * xlo + m2 % SQRT_BASE * SQRT_BASE + carry;
+          carry = (temp / base | 0) + (m2 / SQRT_BASE | 0) + khi * xhi;
+          x2[i3] = temp % base;
+        }
+        if (carry) x2 = [carry].concat(x2);
+        return x2;
+      }
+      function compare2(a2, b2, aL, bL) {
+        var i3, cmp;
+        if (aL != bL) {
+          cmp = aL > bL ? 1 : -1;
+        } else {
+          for (i3 = cmp = 0; i3 < aL; i3++) {
+            if (a2[i3] != b2[i3]) {
+              cmp = a2[i3] > b2[i3] ? 1 : -1;
+              break;
+            }
+          }
+        }
+        return cmp;
+      }
+      function subtract(a2, b2, aL, base) {
+        var i3 = 0;
+        for (; aL--; ) {
+          a2[aL] -= i3;
+          i3 = a2[aL] < b2[aL] ? 1 : 0;
+          a2[aL] = i3 * base + a2[aL] - b2[aL];
+        }
+        for (; !a2[0] && a2.length > 1; a2.splice(0, 1)) ;
       }
-      if (this._strict) {
-        throw new Error(`validateLocation:  Invalid location: "${location}".`);
+      return function(x2, y2, dp, rm, base) {
+        var cmp, e3, i3, more, n3, prod, prodL, q2, qc, rem, remL, rem0, xi, xL, yc0, yL, yz, s2 = x2.s == y2.s ? 1 : -1, xc = x2.c, yc = y2.c;
+        if (!xc || !xc[0] || !yc || !yc[0]) {
+          return new BigNumber2(
+            // Return NaN if either NaN, or both Infinity or 0.
+            !x2.s || !y2.s || (xc ? yc && xc[0] == yc[0] : !yc) ? NaN : (
+              // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0.
+              xc && xc[0] == 0 || !yc ? s2 * 0 : s2 / 0
+            )
+          );
+        }
+        q2 = new BigNumber2(s2);
+        qc = q2.c = [];
+        e3 = x2.e - y2.e;
+        s2 = dp + e3 + 1;
+        if (!base) {
+          base = BASE;
+          e3 = bitFloor(x2.e / LOG_BASE) - bitFloor(y2.e / LOG_BASE);
+          s2 = s2 / LOG_BASE | 0;
+        }
+        for (i3 = 0; yc[i3] == (xc[i3] || 0); i3++) ;
+        if (yc[i3] > (xc[i3] || 0)) e3--;
+        if (s2 < 0) {
+          qc.push(1);
+          more = true;
+        } else {
+          xL = xc.length;
+          yL = yc.length;
+          i3 = 0;
+          s2 += 2;
+          n3 = mathfloor(base / (yc[0] + 1));
+          if (n3 > 1) {
+            yc = multiply(yc, n3, base);
+            xc = multiply(xc, n3, base);
+            yL = yc.length;
+            xL = xc.length;
+          }
+          xi = yL;
+          rem = xc.slice(0, yL);
+          remL = rem.length;
+          for (; remL < yL; rem[remL++] = 0) ;
+          yz = yc.slice();
+          yz = [0].concat(yz);
+          yc0 = yc[0];
+          if (yc[1] >= base / 2) yc0++;
+          do {
+            n3 = 0;
+            cmp = compare2(yc, rem, yL, remL);
+            if (cmp < 0) {
+              rem0 = rem[0];
+              if (yL != remL) rem0 = rem0 * base + (rem[1] || 0);
+              n3 = mathfloor(rem0 / yc0);
+              if (n3 > 1) {
+                if (n3 >= base) n3 = base - 1;
+                prod = multiply(yc, n3, base);
+                prodL = prod.length;
+                remL = rem.length;
+                while (compare2(prod, rem, prodL, remL) == 1) {
+                  n3--;
+                  subtract(prod, yL < prodL ? yz : yc, prodL, base);
+                  prodL = prod.length;
+                  cmp = 1;
+                }
+              } else {
+                if (n3 == 0) {
+                  cmp = n3 = 1;
+                }
+                prod = yc.slice();
+                prodL = prod.length;
+              }
+              if (prodL < remL) prod = [0].concat(prod);
+              subtract(rem, prod, remL, base);
+              remL = rem.length;
+              if (cmp == -1) {
+                while (compare2(yc, rem, yL, remL) < 1) {
+                  n3++;
+                  subtract(rem, yL < remL ? yz : yc, remL, base);
+                  remL = rem.length;
+                }
+              }
+            } else if (cmp === 0) {
+              n3++;
+              rem = [0];
+            }
+            qc[i3++] = n3;
+            if (rem[0]) {
+              rem[remL++] = xc[xi] || 0;
+            } else {
+              rem = [xc[xi]];
+              remL = 1;
+            }
+          } while ((xi++ < xL || rem[0] != null) && s2--);
+          more = rem[0] != null;
+          if (!qc[0]) qc.splice(0, 1);
+        }
+        if (base == BASE) {
+          for (i3 = 1, s2 = qc[0]; s2 >= 10; s2 /= 10, i3++) ;
+          round(q2, dp + (q2.e = i3 + e3 * LOG_BASE - 1) + 1, rm, more);
+        } else {
+          q2.e = e3;
+          q2.r = +more;
+        }
+        return q2;
+      };
+    }();
+    function format2(n3, i3, rm, id2) {
+      var c0, e3, ne2, len, str;
+      if (rm == null) rm = ROUNDING_MODE;
+      else intCheck(rm, 0, 8);
+      if (!n3.c) return n3.toString();
+      c0 = n3.c[0];
+      ne2 = n3.e;
+      if (i3 == null) {
+        str = coeffToString(n3.c);
+        str = id2 == 1 || id2 == 2 && (ne2 <= TO_EXP_NEG || ne2 >= TO_EXP_POS) ? toExponential(str, ne2) : toFixedPoint(str, ne2, "0");
       } else {
-        return null;
+        n3 = round(new BigNumber2(n3), i3, rm);
+        e3 = n3.e;
+        str = coeffToString(n3.c);
+        len = str.length;
+        if (id2 == 1 || id2 == 2 && (i3 <= e3 || e3 <= TO_EXP_NEG)) {
+          for (; len < i3; str += "0", len++) ;
+          str = toExponential(str, e3);
+        } else {
+          i3 -= ne2;
+          str = toFixedPoint(str, e3, "0");
+          if (e3 + 1 > len) {
+            if (--i3 > 0) for (str += "."; i3--; str += "0") ;
+          } else {
+            i3 += e3 - len;
+            if (i3 > 0) {
+              if (e3 + 1 == len) str += ".";
+              for (; i3--; str += "0") ;
+            }
+          }
+        }
       }
+      return n3.s < 0 && c0 ? "-" + str : str;
     }
-    resolveLocation(location) {
-      const valid = this.validateLocation(location);
-      if (!valid)
-        return null;
-      const id2 = valid.id;
-      if (this._cache[id2]) {
-        return Object.assign(valid, { feature: this._cache[id2] });
-      }
-      if (valid.type === "point") {
-        const lon = location[0];
-        const lat = location[1];
-        const radius = location[2] || 25;
-        const EDGES = 10;
-        const PRECISION = 3;
-        const area = Math.PI * radius * radius;
-        const feature3 = this._cache[id2] = (0, import_geojson_precision.default)({
-          type: "Feature",
-          id: id2,
-          properties: { id: id2, area: Number(area.toFixed(2)) },
-          geometry: (0, import_circle_to_polygon.default)([lon, lat], radius * 1e3, EDGES)
-        }, PRECISION);
-        return Object.assign(valid, { feature: feature3 });
-      } else if (valid.type === "geojson") {
-      } else if (valid.type === "countrycoder") {
-        let feature3 = _cloneDeep(feature(id2));
-        let props = feature3.properties;
-        if (Array.isArray(props.members)) {
-          let aggregate = aggregateFeature(id2);
-          aggregate.geometry.coordinates = _clip([aggregate], "UNION").geometry.coordinates;
-          feature3.geometry = aggregate.geometry;
-        }
-        if (!props.area) {
-          const area = import_geojson_area.default.geometry(feature3.geometry) / 1e6;
-          props.area = Number(area.toFixed(2));
+    function maxOrMin(args, n3) {
+      var k2, y2, i3 = 1, x2 = new BigNumber2(args[0]);
+      for (; i3 < args.length; i3++) {
+        y2 = new BigNumber2(args[i3]);
+        if (!y2.s || (k2 = compare(x2, y2)) === n3 || k2 === 0 && x2.s === n3) {
+          x2 = y2;
         }
-        feature3.id = id2;
-        props.id = id2;
-        this._cache[id2] = feature3;
-        return Object.assign(valid, { feature: feature3 });
       }
-      if (this._strict) {
-        throw new Error(`resolveLocation:  Couldn't resolve location "${location}".`);
+      return x2;
+    }
+    function normalise(n3, c2, e3) {
+      var i3 = 1, j2 = c2.length;
+      for (; !c2[--j2]; c2.pop()) ;
+      for (j2 = c2[0]; j2 >= 10; j2 /= 10, i3++) ;
+      if ((e3 = i3 + e3 * LOG_BASE - 1) > MAX_EXP) {
+        n3.c = n3.e = null;
+      } else if (e3 < MIN_EXP) {
+        n3.c = [n3.e = 0];
       } else {
-        return null;
+        n3.e = e3;
+        n3.c = c2;
       }
+      return n3;
     }
-    validateLocationSet(locationSet) {
-      locationSet = locationSet || {};
-      const validator = this.validateLocation.bind(this);
-      let include = (locationSet.include || []).map(validator).filter(Boolean);
-      let exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
-      if (!include.length) {
-        if (this._strict) {
-          throw new Error(`validateLocationSet:  LocationSet includes nothing.`);
+    parseNumeric2 = /* @__PURE__ */ function() {
+      var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, dotAfter = /^([^.]+)\.$/, dotBefore = /^\.([^.]+)$/, isInfinityOrNaN = /^-?(Infinity|NaN)$/, whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g;
+      return function(x2, str, isNum, b2) {
+        var base, s2 = isNum ? str : str.replace(whitespaceOrPlus, "");
+        if (isInfinityOrNaN.test(s2)) {
+          x2.s = isNaN(s2) ? null : s2 < 0 ? -1 : 1;
         } else {
-          locationSet.include = ["Q2"];
-          include = [{ type: "countrycoder", location: "Q2", id: "Q2" }];
+          if (!isNum) {
+            s2 = s2.replace(basePrefix, function(m2, p1, p2) {
+              base = (p2 = p2.toLowerCase()) == "x" ? 16 : p2 == "b" ? 2 : 8;
+              return !b2 || b2 == base ? p1 : m2;
+            });
+            if (b2) {
+              base = b2;
+              s2 = s2.replace(dotAfter, "$1").replace(dotBefore, "0.$1");
+            }
+            if (str != s2) return new BigNumber2(s2, base);
+          }
+          if (BigNumber2.DEBUG) {
+            throw Error(bignumberError + "Not a" + (b2 ? " base " + b2 : "") + " number: " + str);
+          }
+          x2.s = null;
+        }
+        x2.c = x2.e = null;
+      };
+    }();
+    function round(x2, sd, rm, r2) {
+      var d2, i3, j2, k2, n3, ni, rd, xc = x2.c, pows10 = POWS_TEN;
+      if (xc) {
+        out: {
+          for (d2 = 1, k2 = xc[0]; k2 >= 10; k2 /= 10, d2++) ;
+          i3 = sd - d2;
+          if (i3 < 0) {
+            i3 += LOG_BASE;
+            j2 = sd;
+            n3 = xc[ni = 0];
+            rd = mathfloor(n3 / pows10[d2 - j2 - 1] % 10);
+          } else {
+            ni = mathceil((i3 + 1) / LOG_BASE);
+            if (ni >= xc.length) {
+              if (r2) {
+                for (; xc.length <= ni; xc.push(0)) ;
+                n3 = rd = 0;
+                d2 = 1;
+                i3 %= LOG_BASE;
+                j2 = i3 - LOG_BASE + 1;
+              } else {
+                break out;
+              }
+            } else {
+              n3 = k2 = xc[ni];
+              for (d2 = 1; k2 >= 10; k2 /= 10, d2++) ;
+              i3 %= LOG_BASE;
+              j2 = i3 - LOG_BASE + d2;
+              rd = j2 < 0 ? 0 : mathfloor(n3 / pows10[d2 - j2 - 1] % 10);
+            }
+          }
+          r2 = r2 || sd < 0 || // Are there any non-zero digits after the rounding digit?
+          // The expression  n % pows10[d - j - 1]  returns all digits of n to the right
+          // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714.
+          xc[ni + 1] != null || (j2 < 0 ? n3 : n3 % pows10[d2 - j2 - 1]);
+          r2 = rm < 4 ? (rd || r2) && (rm == 0 || rm == (x2.s < 0 ? 3 : 2)) : rd > 5 || rd == 5 && (rm == 4 || r2 || rm == 6 && // Check whether the digit to the left of the rounding digit is odd.
+          (i3 > 0 ? j2 > 0 ? n3 / pows10[d2 - j2] : 0 : xc[ni - 1]) % 10 & 1 || rm == (x2.s < 0 ? 8 : 7));
+          if (sd < 1 || !xc[0]) {
+            xc.length = 0;
+            if (r2) {
+              sd -= x2.e + 1;
+              xc[0] = pows10[(LOG_BASE - sd % LOG_BASE) % LOG_BASE];
+              x2.e = -sd || 0;
+            } else {
+              xc[0] = x2.e = 0;
+            }
+            return x2;
+          }
+          if (i3 == 0) {
+            xc.length = ni;
+            k2 = 1;
+            ni--;
+          } else {
+            xc.length = ni + 1;
+            k2 = pows10[LOG_BASE - i3];
+            xc[ni] = j2 > 0 ? mathfloor(n3 / pows10[d2 - j2] % pows10[j2]) * k2 : 0;
+          }
+          if (r2) {
+            for (; ; ) {
+              if (ni == 0) {
+                for (i3 = 1, j2 = xc[0]; j2 >= 10; j2 /= 10, i3++) ;
+                j2 = xc[0] += k2;
+                for (k2 = 1; j2 >= 10; j2 /= 10, k2++) ;
+                if (i3 != k2) {
+                  x2.e++;
+                  if (xc[0] == BASE) xc[0] = 1;
+                }
+                break;
+              } else {
+                xc[ni] += k2;
+                if (xc[ni] != BASE) break;
+                xc[ni--] = 0;
+                k2 = 1;
+              }
+            }
+          }
+          for (i3 = xc.length; xc[--i3] === 0; xc.pop()) ;
+        }
+        if (x2.e > MAX_EXP) {
+          x2.c = x2.e = null;
+        } else if (x2.e < MIN_EXP) {
+          x2.c = [x2.e = 0];
+        }
+      }
+      return x2;
+    }
+    function valueOf(n3) {
+      var str, e3 = n3.e;
+      if (e3 === null) return n3.toString();
+      str = coeffToString(n3.c);
+      str = e3 <= TO_EXP_NEG || e3 >= TO_EXP_POS ? toExponential(str, e3) : toFixedPoint(str, e3, "0");
+      return n3.s < 0 ? "-" + str : str;
+    }
+    P2.absoluteValue = P2.abs = function() {
+      var x2 = new BigNumber2(this);
+      if (x2.s < 0) x2.s = 1;
+      return x2;
+    };
+    P2.comparedTo = function(y2, b2) {
+      return compare(this, new BigNumber2(y2, b2));
+    };
+    P2.decimalPlaces = P2.dp = function(dp, rm) {
+      var c2, n3, v2, x2 = this;
+      if (dp != null) {
+        intCheck(dp, 0, MAX);
+        if (rm == null) rm = ROUNDING_MODE;
+        else intCheck(rm, 0, 8);
+        return round(new BigNumber2(x2), dp + x2.e + 1, rm);
+      }
+      if (!(c2 = x2.c)) return null;
+      n3 = ((v2 = c2.length - 1) - bitFloor(this.e / LOG_BASE)) * LOG_BASE;
+      if (v2 = c2[v2]) for (; v2 % 10 == 0; v2 /= 10, n3--) ;
+      if (n3 < 0) n3 = 0;
+      return n3;
+    };
+    P2.dividedBy = P2.div = function(y2, b2) {
+      return div(this, new BigNumber2(y2, b2), DECIMAL_PLACES, ROUNDING_MODE);
+    };
+    P2.dividedToIntegerBy = P2.idiv = function(y2, b2) {
+      return div(this, new BigNumber2(y2, b2), 0, 1);
+    };
+    P2.exponentiatedBy = P2.pow = function(n3, m2) {
+      var half, isModExp, i3, k2, more, nIsBig, nIsNeg, nIsOdd, y2, x2 = this;
+      n3 = new BigNumber2(n3);
+      if (n3.c && !n3.isInteger()) {
+        throw Error(bignumberError + "Exponent not an integer: " + valueOf(n3));
+      }
+      if (m2 != null) m2 = new BigNumber2(m2);
+      nIsBig = n3.e > 14;
+      if (!x2.c || !x2.c[0] || x2.c[0] == 1 && !x2.e && x2.c.length == 1 || !n3.c || !n3.c[0]) {
+        y2 = new BigNumber2(Math.pow(+valueOf(x2), nIsBig ? n3.s * (2 - isOdd(n3)) : +valueOf(n3)));
+        return m2 ? y2.mod(m2) : y2;
+      }
+      nIsNeg = n3.s < 0;
+      if (m2) {
+        if (m2.c ? !m2.c[0] : !m2.s) return new BigNumber2(NaN);
+        isModExp = !nIsNeg && x2.isInteger() && m2.isInteger();
+        if (isModExp) x2 = x2.mod(m2);
+      } else if (n3.e > 9 && (x2.e > 0 || x2.e < -1 || (x2.e == 0 ? x2.c[0] > 1 || nIsBig && x2.c[1] >= 24e7 : x2.c[0] < 8e13 || nIsBig && x2.c[0] <= 9999975e7))) {
+        k2 = x2.s < 0 && isOdd(n3) ? -0 : 0;
+        if (x2.e > -1) k2 = 1 / k2;
+        return new BigNumber2(nIsNeg ? 1 / k2 : k2);
+      } else if (POW_PRECISION) {
+        k2 = mathceil(POW_PRECISION / LOG_BASE + 2);
+      }
+      if (nIsBig) {
+        half = new BigNumber2(0.5);
+        if (nIsNeg) n3.s = 1;
+        nIsOdd = isOdd(n3);
+      } else {
+        i3 = Math.abs(+valueOf(n3));
+        nIsOdd = i3 % 2;
+      }
+      y2 = new BigNumber2(ONE);
+      for (; ; ) {
+        if (nIsOdd) {
+          y2 = y2.times(x2);
+          if (!y2.c) break;
+          if (k2) {
+            if (y2.c.length > k2) y2.c.length = k2;
+          } else if (isModExp) {
+            y2 = y2.mod(m2);
+          }
+        }
+        if (i3) {
+          i3 = mathfloor(i3 / 2);
+          if (i3 === 0) break;
+          nIsOdd = i3 % 2;
+        } else {
+          n3 = n3.times(half);
+          round(n3, n3.e + 1, 1);
+          if (n3.e > 14) {
+            nIsOdd = isOdd(n3);
+          } else {
+            i3 = +valueOf(n3);
+            if (i3 === 0) break;
+            nIsOdd = i3 % 2;
+          }
+        }
+        x2 = x2.times(x2);
+        if (k2) {
+          if (x2.c && x2.c.length > k2) x2.c.length = k2;
+        } else if (isModExp) {
+          x2 = x2.mod(m2);
         }
       }
-      include.sort(_sortLocations);
-      let id2 = "+[" + include.map((d) => d.id).join(",") + "]";
-      if (exclude.length) {
-        exclude.sort(_sortLocations);
-        id2 += "-[" + exclude.map((d) => d.id).join(",") + "]";
+      if (isModExp) return y2;
+      if (nIsNeg) y2 = ONE.div(y2);
+      return m2 ? y2.mod(m2) : k2 ? round(y2, POW_PRECISION, ROUNDING_MODE, more) : y2;
+    };
+    P2.integerValue = function(rm) {
+      var n3 = new BigNumber2(this);
+      if (rm == null) rm = ROUNDING_MODE;
+      else intCheck(rm, 0, 8);
+      return round(n3, n3.e + 1, rm);
+    };
+    P2.isEqualTo = P2.eq = function(y2, b2) {
+      return compare(this, new BigNumber2(y2, b2)) === 0;
+    };
+    P2.isFinite = function() {
+      return !!this.c;
+    };
+    P2.isGreaterThan = P2.gt = function(y2, b2) {
+      return compare(this, new BigNumber2(y2, b2)) > 0;
+    };
+    P2.isGreaterThanOrEqualTo = P2.gte = function(y2, b2) {
+      return (b2 = compare(this, new BigNumber2(y2, b2))) === 1 || b2 === 0;
+    };
+    P2.isInteger = function() {
+      return !!this.c && bitFloor(this.e / LOG_BASE) > this.c.length - 2;
+    };
+    P2.isLessThan = P2.lt = function(y2, b2) {
+      return compare(this, new BigNumber2(y2, b2)) < 0;
+    };
+    P2.isLessThanOrEqualTo = P2.lte = function(y2, b2) {
+      return (b2 = compare(this, new BigNumber2(y2, b2))) === -1 || b2 === 0;
+    };
+    P2.isNaN = function() {
+      return !this.s;
+    };
+    P2.isNegative = function() {
+      return this.s < 0;
+    };
+    P2.isPositive = function() {
+      return this.s > 0;
+    };
+    P2.isZero = function() {
+      return !!this.c && this.c[0] == 0;
+    };
+    P2.minus = function(y2, b2) {
+      var i3, j2, t2, xLTy, x2 = this, a2 = x2.s;
+      y2 = new BigNumber2(y2, b2);
+      b2 = y2.s;
+      if (!a2 || !b2) return new BigNumber2(NaN);
+      if (a2 != b2) {
+        y2.s = -b2;
+        return x2.plus(y2);
       }
-      return { type: "locationset", locationSet, id: id2 };
-    }
-    resolveLocationSet(locationSet) {
-      locationSet = locationSet || {};
-      const valid = this.validateLocationSet(locationSet);
-      if (!valid)
-        return null;
-      const id2 = valid.id;
-      if (this._cache[id2]) {
-        return Object.assign(valid, { feature: this._cache[id2] });
+      var xe2 = x2.e / LOG_BASE, ye2 = y2.e / LOG_BASE, xc = x2.c, yc = y2.c;
+      if (!xe2 || !ye2) {
+        if (!xc || !yc) return xc ? (y2.s = -b2, y2) : new BigNumber2(yc ? x2 : NaN);
+        if (!xc[0] || !yc[0]) {
+          return yc[0] ? (y2.s = -b2, y2) : new BigNumber2(xc[0] ? x2 : (
+            // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity
+            ROUNDING_MODE == 3 ? -0 : 0
+          ));
+        }
       }
-      const resolver = this.resolveLocation.bind(this);
-      const includes = (locationSet.include || []).map(resolver).filter(Boolean);
-      const excludes = (locationSet.exclude || []).map(resolver).filter(Boolean);
-      if (includes.length === 1 && excludes.length === 0) {
-        return Object.assign(valid, { feature: includes[0].feature });
+      xe2 = bitFloor(xe2);
+      ye2 = bitFloor(ye2);
+      xc = xc.slice();
+      if (a2 = xe2 - ye2) {
+        if (xLTy = a2 < 0) {
+          a2 = -a2;
+          t2 = xc;
+        } else {
+          ye2 = xe2;
+          t2 = yc;
+        }
+        t2.reverse();
+        for (b2 = a2; b2--; t2.push(0)) ;
+        t2.reverse();
+      } else {
+        j2 = (xLTy = (a2 = xc.length) < (b2 = yc.length)) ? a2 : b2;
+        for (a2 = b2 = 0; b2 < j2; b2++) {
+          if (xc[b2] != yc[b2]) {
+            xLTy = xc[b2] < yc[b2];
+            break;
+          }
+        }
       }
-      const includeGeoJSON = _clip(includes.map((d) => d.feature), "UNION");
-      const excludeGeoJSON = _clip(excludes.map((d) => d.feature), "UNION");
-      let resultGeoJSON = excludeGeoJSON ? _clip([includeGeoJSON, excludeGeoJSON], "DIFFERENCE") : includeGeoJSON;
-      const area = import_geojson_area.default.geometry(resultGeoJSON.geometry) / 1e6;
-      resultGeoJSON.id = id2;
-      resultGeoJSON.properties = { id: id2, area: Number(area.toFixed(2)) };
-      this._cache[id2] = resultGeoJSON;
-      return Object.assign(valid, { feature: resultGeoJSON });
-    }
-    strict(val) {
-      if (val === void 0) {
-        return this._strict;
+      if (xLTy) {
+        t2 = xc;
+        xc = yc;
+        yc = t2;
+        y2.s = -y2.s;
+      }
+      b2 = (j2 = yc.length) - (i3 = xc.length);
+      if (b2 > 0) for (; b2--; xc[i3++] = 0) ;
+      b2 = BASE - 1;
+      for (; j2 > a2; ) {
+        if (xc[--j2] < yc[j2]) {
+          for (i3 = j2; i3 && !xc[--i3]; xc[i3] = b2) ;
+          --xc[i3];
+          xc[j2] += BASE;
+        }
+        xc[j2] -= yc[j2];
+      }
+      for (; xc[0] == 0; xc.splice(0, 1), --ye2) ;
+      if (!xc[0]) {
+        y2.s = ROUNDING_MODE == 3 ? -1 : 1;
+        y2.c = [y2.e = 0];
+        return y2;
+      }
+      return normalise(y2, xc, ye2);
+    };
+    P2.modulo = P2.mod = function(y2, b2) {
+      var q2, s2, x2 = this;
+      y2 = new BigNumber2(y2, b2);
+      if (!x2.c || !y2.s || y2.c && !y2.c[0]) {
+        return new BigNumber2(NaN);
+      } else if (!y2.c || x2.c && !x2.c[0]) {
+        return new BigNumber2(x2);
+      }
+      if (MODULO_MODE == 9) {
+        s2 = y2.s;
+        y2.s = 1;
+        q2 = div(x2, y2, 0, 3);
+        y2.s = s2;
+        q2.s *= s2;
       } else {
-        this._strict = val;
-        return this;
+        q2 = div(x2, y2, 0, MODULO_MODE);
       }
-    }
-    cache() {
-      return this._cache;
-    }
-    stringify(obj, options2) {
-      return (0, import_json_stringify_pretty_compact.default)(obj, options2);
-    }
-  };
-  function _clip(features2, which) {
-    if (!Array.isArray(features2) || !features2.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 coords = fn.apply(null, args);
-    return {
-      type: "Feature",
-      properties: {},
-      geometry: {
-        type: whichType(coords),
-        coordinates: coords
+      y2 = x2.minus(q2.times(y2));
+      if (!y2.c[0] && MODULO_MODE == 1) y2.s = x2.s;
+      return y2;
+    };
+    P2.multipliedBy = P2.times = function(y2, b2) {
+      var c2, e3, i3, j2, k2, m2, xcL, xlo, xhi, ycL, ylo, yhi, zc, base, sqrtBase, x2 = this, xc = x2.c, yc = (y2 = new BigNumber2(y2, b2)).c;
+      if (!xc || !yc || !xc[0] || !yc[0]) {
+        if (!x2.s || !y2.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc) {
+          y2.c = y2.e = y2.s = null;
+        } else {
+          y2.s *= x2.s;
+          if (!xc || !yc) {
+            y2.c = y2.e = null;
+          } else {
+            y2.c = [0];
+            y2.e = 0;
+          }
+        }
+        return y2;
+      }
+      e3 = bitFloor(x2.e / LOG_BASE) + bitFloor(y2.e / LOG_BASE);
+      y2.s *= x2.s;
+      xcL = xc.length;
+      ycL = yc.length;
+      if (xcL < ycL) {
+        zc = xc;
+        xc = yc;
+        yc = zc;
+        i3 = xcL;
+        xcL = ycL;
+        ycL = i3;
+      }
+      for (i3 = xcL + ycL, zc = []; i3--; zc.push(0)) ;
+      base = BASE;
+      sqrtBase = SQRT_BASE;
+      for (i3 = ycL; --i3 >= 0; ) {
+        c2 = 0;
+        ylo = yc[i3] % sqrtBase;
+        yhi = yc[i3] / sqrtBase | 0;
+        for (k2 = xcL, j2 = i3 + k2; j2 > i3; ) {
+          xlo = xc[--k2] % sqrtBase;
+          xhi = xc[k2] / sqrtBase | 0;
+          m2 = yhi * xlo + xhi * ylo;
+          xlo = ylo * xlo + m2 % sqrtBase * sqrtBase + zc[j2] + c2;
+          c2 = (xlo / base | 0) + (m2 / sqrtBase | 0) + yhi * xhi;
+          zc[j2--] = xlo % base;
+        }
+        zc[j2] = c2;
+      }
+      if (c2) {
+        ++e3;
+      } else {
+        zc.splice(0, 1);
+      }
+      return normalise(y2, zc, e3);
+    };
+    P2.negated = function() {
+      var x2 = new BigNumber2(this);
+      x2.s = -x2.s || null;
+      return x2;
+    };
+    P2.plus = function(y2, b2) {
+      var t2, x2 = this, a2 = x2.s;
+      y2 = new BigNumber2(y2, b2);
+      b2 = y2.s;
+      if (!a2 || !b2) return new BigNumber2(NaN);
+      if (a2 != b2) {
+        y2.s = -b2;
+        return x2.minus(y2);
+      }
+      var xe2 = x2.e / LOG_BASE, ye2 = y2.e / LOG_BASE, xc = x2.c, yc = y2.c;
+      if (!xe2 || !ye2) {
+        if (!xc || !yc) return new BigNumber2(a2 / 0);
+        if (!xc[0] || !yc[0]) return yc[0] ? y2 : new BigNumber2(xc[0] ? x2 : a2 * 0);
+      }
+      xe2 = bitFloor(xe2);
+      ye2 = bitFloor(ye2);
+      xc = xc.slice();
+      if (a2 = xe2 - ye2) {
+        if (a2 > 0) {
+          ye2 = xe2;
+          t2 = yc;
+        } else {
+          a2 = -a2;
+          t2 = xc;
+        }
+        t2.reverse();
+        for (; a2--; t2.push(0)) ;
+        t2.reverse();
+      }
+      a2 = xc.length;
+      b2 = yc.length;
+      if (a2 - b2 < 0) {
+        t2 = yc;
+        yc = xc;
+        xc = t2;
+        b2 = a2;
+      }
+      for (a2 = 0; b2; ) {
+        a2 = (xc[--b2] = xc[b2] + yc[b2] + a2) / BASE | 0;
+        xc[b2] = BASE === xc[b2] ? 0 : xc[b2] % BASE;
+      }
+      if (a2) {
+        xc = [a2].concat(xc);
+        ++ye2;
+      }
+      return normalise(y2, xc, ye2);
+    };
+    P2.precision = P2.sd = function(sd, rm) {
+      var c2, n3, v2, x2 = this;
+      if (sd != null && sd !== !!sd) {
+        intCheck(sd, 1, MAX);
+        if (rm == null) rm = ROUNDING_MODE;
+        else intCheck(rm, 0, 8);
+        return round(new BigNumber2(x2), sd, rm);
+      }
+      if (!(c2 = x2.c)) return null;
+      v2 = c2.length - 1;
+      n3 = v2 * LOG_BASE + 1;
+      if (v2 = c2[v2]) {
+        for (; v2 % 10 == 0; v2 /= 10, n3--) ;
+        for (v2 = c2[0]; v2 >= 10; v2 /= 10, n3++) ;
+      }
+      if (sd && x2.e + 1 > n3) n3 = x2.e + 1;
+      return n3;
+    };
+    P2.shiftedBy = function(k2) {
+      intCheck(k2, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER);
+      return this.times("1e" + k2);
+    };
+    P2.squareRoot = P2.sqrt = function() {
+      var m2, n3, r2, rep, t2, x2 = this, c2 = x2.c, s2 = x2.s, e3 = x2.e, dp = DECIMAL_PLACES + 4, half = new BigNumber2("0.5");
+      if (s2 !== 1 || !c2 || !c2[0]) {
+        return new BigNumber2(!s2 || s2 < 0 && (!c2 || c2[0]) ? NaN : c2 ? x2 : 1 / 0);
+      }
+      s2 = Math.sqrt(+valueOf(x2));
+      if (s2 == 0 || s2 == 1 / 0) {
+        n3 = coeffToString(c2);
+        if ((n3.length + e3) % 2 == 0) n3 += "0";
+        s2 = Math.sqrt(+n3);
+        e3 = bitFloor((e3 + 1) / 2) - (e3 < 0 || e3 % 2);
+        if (s2 == 1 / 0) {
+          n3 = "5e" + e3;
+        } else {
+          n3 = s2.toExponential();
+          n3 = n3.slice(0, n3.indexOf("e") + 1) + e3;
+        }
+        r2 = new BigNumber2(n3);
+      } else {
+        r2 = new BigNumber2(s2 + "");
+      }
+      if (r2.c[0]) {
+        e3 = r2.e;
+        s2 = e3 + dp;
+        if (s2 < 3) s2 = 0;
+        for (; ; ) {
+          t2 = r2;
+          r2 = half.times(t2.plus(div(x2, t2, dp, 1)));
+          if (coeffToString(t2.c).slice(0, s2) === (n3 = coeffToString(r2.c)).slice(0, s2)) {
+            if (r2.e < e3) --s2;
+            n3 = n3.slice(s2 - 3, s2 + 1);
+            if (n3 == "9999" || !rep && n3 == "4999") {
+              if (!rep) {
+                round(t2, t2.e + DECIMAL_PLACES + 2, 0);
+                if (t2.times(t2).eq(x2)) {
+                  r2 = t2;
+                  break;
+                }
+              }
+              dp += 4;
+              s2 += 4;
+              rep = 1;
+            } else {
+              if (!+n3 || !+n3.slice(1) && n3.charAt(0) == "5") {
+                round(r2, r2.e + DECIMAL_PLACES + 2, 1);
+                m2 = !r2.times(r2).eq(x2);
+              }
+              break;
+            }
+          }
+        }
       }
+      return round(r2, r2.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m2);
     };
-    function whichType(coords2) {
-      const a = Array.isArray(coords2);
-      const b = a && Array.isArray(coords2[0]);
-      const c = b && Array.isArray(coords2[0][0]);
-      const d = c && Array.isArray(coords2[0][0][0]);
-      return d ? "MultiPolygon" : "Polygon";
+    P2.toExponential = function(dp, rm) {
+      if (dp != null) {
+        intCheck(dp, 0, MAX);
+        dp++;
+      }
+      return format2(this, dp, rm, 1);
+    };
+    P2.toFixed = function(dp, rm) {
+      if (dp != null) {
+        intCheck(dp, 0, MAX);
+        dp = dp + this.e + 1;
+      }
+      return format2(this, dp, rm);
+    };
+    P2.toFormat = function(dp, rm, format3) {
+      var str, x2 = this;
+      if (format3 == null) {
+        if (dp != null && rm && typeof rm == "object") {
+          format3 = rm;
+          rm = null;
+        } else if (dp && typeof dp == "object") {
+          format3 = dp;
+          dp = rm = null;
+        } else {
+          format3 = FORMAT;
+        }
+      } else if (typeof format3 != "object") {
+        throw Error(bignumberError + "Argument not an object: " + format3);
+      }
+      str = x2.toFixed(dp, rm);
+      if (x2.c) {
+        var i3, arr = str.split("."), g1 = +format3.groupSize, g22 = +format3.secondaryGroupSize, groupSeparator = format3.groupSeparator || "", intPart = arr[0], fractionPart = arr[1], isNeg = x2.s < 0, intDigits = isNeg ? intPart.slice(1) : intPart, len = intDigits.length;
+        if (g22) {
+          i3 = g1;
+          g1 = g22;
+          g22 = i3;
+          len -= i3;
+        }
+        if (g1 > 0 && len > 0) {
+          i3 = len % g1 || g1;
+          intPart = intDigits.substr(0, i3);
+          for (; i3 < len; i3 += g1) intPart += groupSeparator + intDigits.substr(i3, g1);
+          if (g22 > 0) intPart += groupSeparator + intDigits.slice(i3);
+          if (isNeg) intPart = "-" + intPart;
+        }
+        str = fractionPart ? intPart + (format3.decimalSeparator || "") + ((g22 = +format3.fractionGroupSize) ? fractionPart.replace(
+          new RegExp("\\d{" + g22 + "}\\B", "g"),
+          "$&" + (format3.fractionGroupSeparator || "")
+        ) : fractionPart) : intPart;
+      }
+      return (format3.prefix || "") + str + (format3.suffix || "");
+    };
+    P2.toFraction = function(md) {
+      var d2, d0, d1, d22, e3, exp2, n3, n0, n1, q2, r2, s2, x2 = this, xc = x2.c;
+      if (md != null) {
+        n3 = new BigNumber2(md);
+        if (!n3.isInteger() && (n3.c || n3.s !== 1) || n3.lt(ONE)) {
+          throw Error(bignumberError + "Argument " + (n3.isInteger() ? "out of range: " : "not an integer: ") + valueOf(n3));
+        }
+      }
+      if (!xc) return new BigNumber2(x2);
+      d2 = new BigNumber2(ONE);
+      n1 = d0 = new BigNumber2(ONE);
+      d1 = n0 = new BigNumber2(ONE);
+      s2 = coeffToString(xc);
+      e3 = d2.e = s2.length - x2.e - 1;
+      d2.c[0] = POWS_TEN[(exp2 = e3 % LOG_BASE) < 0 ? LOG_BASE + exp2 : exp2];
+      md = !md || n3.comparedTo(d2) > 0 ? e3 > 0 ? d2 : n1 : n3;
+      exp2 = MAX_EXP;
+      MAX_EXP = 1 / 0;
+      n3 = new BigNumber2(s2);
+      n0.c[0] = 0;
+      for (; ; ) {
+        q2 = div(n3, d2, 0, 1);
+        d22 = d0.plus(q2.times(d1));
+        if (d22.comparedTo(md) == 1) break;
+        d0 = d1;
+        d1 = d22;
+        n1 = n0.plus(q2.times(d22 = n1));
+        n0 = d22;
+        d2 = n3.minus(q2.times(d22 = d2));
+        n3 = d22;
+      }
+      d22 = div(md.minus(d0), d1, 0, 1);
+      n0 = n0.plus(d22.times(n1));
+      d0 = d0.plus(d22.times(d1));
+      n0.s = n1.s = x2.s;
+      e3 = e3 * 2;
+      r2 = div(n1, d1, e3, ROUNDING_MODE).minus(x2).abs().comparedTo(
+        div(n0, d0, e3, ROUNDING_MODE).minus(x2).abs()
+      ) < 1 ? [n1, d1] : [n0, d0];
+      MAX_EXP = exp2;
+      return r2;
+    };
+    P2.toNumber = function() {
+      return +valueOf(this);
+    };
+    P2.toPrecision = function(sd, rm) {
+      if (sd != null) intCheck(sd, 1, MAX);
+      return format2(this, sd, rm, 2);
+    };
+    P2.toString = function(b2) {
+      var str, n3 = this, s2 = n3.s, e3 = n3.e;
+      if (e3 === null) {
+        if (s2) {
+          str = "Infinity";
+          if (s2 < 0) str = "-" + str;
+        } else {
+          str = "NaN";
+        }
+      } else {
+        if (b2 == null) {
+          str = e3 <= TO_EXP_NEG || e3 >= TO_EXP_POS ? toExponential(coeffToString(n3.c), e3) : toFixedPoint(coeffToString(n3.c), e3, "0");
+        } else if (b2 === 10 && alphabetHasNormalDecimalDigits) {
+          n3 = round(new BigNumber2(n3), DECIMAL_PLACES + e3 + 1, ROUNDING_MODE);
+          str = toFixedPoint(coeffToString(n3.c), n3.e, "0");
+        } else {
+          intCheck(b2, 2, ALPHABET.length, "Base");
+          str = convertBase(toFixedPoint(coeffToString(n3.c), e3, "0"), 10, b2, s2, true);
+        }
+        if (s2 < 0 && n3.c[0]) str = "-" + str;
+      }
+      return str;
+    };
+    P2.valueOf = P2.toJSON = function() {
+      return valueOf(this);
+    };
+    P2._isBigNumber = true;
+    P2[Symbol.toStringTag] = "BigNumber";
+    P2[Symbol.for("nodejs.util.inspect.custom")] = P2.valueOf;
+    if (configObject != null) BigNumber2.set(configObject);
+    return BigNumber2;
+  }
+  function bitFloor(n3) {
+    var i3 = n3 | 0;
+    return n3 > 0 || n3 === i3 ? i3 : i3 - 1;
+  }
+  function coeffToString(a2) {
+    var s2, z2, i3 = 1, j2 = a2.length, r2 = a2[0] + "";
+    for (; i3 < j2; ) {
+      s2 = a2[i3++] + "";
+      z2 = LOG_BASE - s2.length;
+      for (; z2--; s2 = "0" + s2) ;
+      r2 += s2;
+    }
+    for (j2 = r2.length; r2.charCodeAt(--j2) === 48; ) ;
+    return r2.slice(0, j2 + 1 || 1);
+  }
+  function compare(x2, y2) {
+    var a2, b2, xc = x2.c, yc = y2.c, i3 = x2.s, j2 = y2.s, k2 = x2.e, l2 = y2.e;
+    if (!i3 || !j2) return null;
+    a2 = xc && !xc[0];
+    b2 = yc && !yc[0];
+    if (a2 || b2) return a2 ? b2 ? 0 : -j2 : i3;
+    if (i3 != j2) return i3;
+    a2 = i3 < 0;
+    b2 = k2 == l2;
+    if (!xc || !yc) return b2 ? 0 : !xc ^ a2 ? 1 : -1;
+    if (!b2) return k2 > l2 ^ a2 ? 1 : -1;
+    j2 = (k2 = xc.length) < (l2 = yc.length) ? k2 : l2;
+    for (i3 = 0; i3 < j2; i3++) if (xc[i3] != yc[i3]) return xc[i3] > yc[i3] ^ a2 ? 1 : -1;
+    return k2 == l2 ? 0 : k2 > l2 ^ a2 ? 1 : -1;
+  }
+  function intCheck(n3, min3, max3, name) {
+    if (n3 < min3 || n3 > max3 || n3 !== mathfloor(n3)) {
+      throw Error(bignumberError + (name || "Argument") + (typeof n3 == "number" ? n3 < min3 || n3 > max3 ? " out of range: " : " not an integer: " : " not a primitive number: ") + String(n3));
+    }
+  }
+  function isOdd(n3) {
+    var k2 = n3.c.length - 1;
+    return bitFloor(n3.e / LOG_BASE) == k2 && n3.c[k2] % 2 != 0;
+  }
+  function toExponential(str, e3) {
+    return (str.length > 1 ? str.charAt(0) + "." + str.slice(1) : str) + (e3 < 0 ? "e" : "e+") + e3;
+  }
+  function toFixedPoint(str, e3, z2) {
+    var len, zs;
+    if (e3 < 0) {
+      for (zs = z2 + "."; ++e3; zs += z2) ;
+      str = zs + str;
+    } else {
+      len = str.length;
+      if (++e3 > len) {
+        for (zs = z2, e3 -= len; --e3; zs += z2) ;
+        str += zs;
+      } else if (e3 < len) {
+        str = str.slice(0, e3) + "." + str.slice(e3);
+      }
     }
+    return str;
   }
-  function _cloneDeep(obj) {
-    return JSON.parse(JSON.stringify(obj));
-  }
-  function _sortLocations(a, b) {
-    const rank = { countrycoder: 1, geojson: 2, point: 3 };
-    const aRank = rank[a.type];
-    const bRank = rank[b.type];
-    return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
-  }
-
-  // modules/core/locations.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;
-  }
+  var BigNumber = clone();
+  var bignumber_default = BigNumber;
 
-  // 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);
-      }
+  // node_modules/splaytree-ts/dist/index.js
+  var SplayTreeNode = class {
+    constructor(key) {
+      __publicField(this, "key");
+      __publicField(this, "left", null);
+      __publicField(this, "right", null);
+      this.key = key;
     }
-    return out;
-    function cleanValue(k2, v2) {
-      function keepSpaces(k3) {
-        return /_hours|_times|:conditional$/.test(k3);
-      }
-      function skip(k3) {
-        return /^(description|note|fixme)$/.test(k3);
-      }
-      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, "");
+  };
+  var SplayTreeSetNode = class extends SplayTreeNode {
+    constructor(key) {
+      super(key);
+    }
+  };
+  var SplayTreeMapNode = class _SplayTreeMapNode extends SplayTreeNode {
+    constructor(key, value) {
+      super(key);
+      __publicField(this, "value");
+      this.value = value;
+    }
+    replaceValue(value) {
+      const node = new _SplayTreeMapNode(this.key, value);
+      node.left = this.left;
+      node.right = this.right;
+      return node;
+    }
+  };
+  var SplayTree = class {
+    constructor() {
+      __publicField(this, "size", 0);
+      __publicField(this, "modificationCount", 0);
+      __publicField(this, "splayCount", 0);
+    }
+    splay(key) {
+      const root3 = this.root;
+      if (root3 == null) {
+        this.compare(key, key);
+        return -1;
       }
-      return cleaned;
+      let right = null;
+      let newTreeRight = null;
+      let left = null;
+      let newTreeLeft = null;
+      let current = root3;
+      const compare2 = this.compare;
+      let comp;
+      while (true) {
+        comp = compare2(current.key, key);
+        if (comp > 0) {
+          let currentLeft = current.left;
+          if (currentLeft == null)
+            break;
+          comp = compare2(currentLeft.key, key);
+          if (comp > 0) {
+            current.left = currentLeft.right;
+            currentLeft.right = current;
+            current = currentLeft;
+            currentLeft = current.left;
+            if (currentLeft == null)
+              break;
+          }
+          if (right == null) {
+            newTreeRight = current;
+          } else {
+            right.left = current;
+          }
+          right = current;
+          current = currentLeft;
+        } else if (comp < 0) {
+          let currentRight = current.right;
+          if (currentRight == null)
+            break;
+          comp = compare2(currentRight.key, key);
+          if (comp < 0) {
+            current.right = currentRight.left;
+            currentRight.left = current;
+            current = currentRight;
+            currentRight = current.right;
+            if (currentRight == null)
+              break;
+          }
+          if (left == null) {
+            newTreeLeft = current;
+          } else {
+            left.right = current;
+          }
+          left = current;
+          current = currentRight;
+        } else {
+          break;
+        }
+      }
+      if (left != null) {
+        left.right = current.left;
+        current.left = newTreeLeft;
+      }
+      if (right != null) {
+        right.left = current.right;
+        current.right = newTreeRight;
+      }
+      if (this.root !== current) {
+        this.root = current;
+        this.splayCount++;
+      }
+      return comp;
     }
-  }
-
-  // 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];
+    splayMin(node) {
+      let current = node;
+      let nextLeft = current.left;
+      while (nextLeft != null) {
+        const left = nextLeft;
+        current.left = left.right;
+        left.right = current;
+        current = left;
+        nextLeft = current.left;
+      }
+      return current;
     }
-    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];
+    splayMax(node) {
+      let current = node;
+      let nextRight = current.right;
+      while (nextRight != null) {
+        const right = nextRight;
+        current.right = right.left;
+        right.left = current;
+        current = right;
+        nextRight = current.right;
       }
+      return current;
     }
-    if (!_detected.browser) {
-      m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);
-      if (m !== null) {
-        _detected.browser = "Opera";
-        _detected.version = m[2];
+    _delete(key) {
+      if (this.root == null)
+        return null;
+      const comp = this.splay(key);
+      if (comp != 0)
+        return null;
+      let root3 = this.root;
+      const result = root3;
+      const left = root3.left;
+      this.size--;
+      if (left == null) {
+        this.root = root3.right;
+      } else {
+        const right = root3.right;
+        root3 = this.splayMax(left);
+        root3.right = right;
+        this.root = root3;
       }
+      this.modificationCount++;
+      return result;
     }
-    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];
+    addNewRoot(node, comp) {
+      this.size++;
+      this.modificationCount++;
+      const root3 = this.root;
+      if (root3 == null) {
+        this.root = node;
+        return;
+      }
+      if (comp < 0) {
+        node.left = root3;
+        node.right = root3.right;
+        root3.right = null;
+      } else {
+        node.right = root3;
+        node.left = root3.left;
+        root3.left = null;
       }
+      this.root = node;
     }
-    if (!_detected.browser) {
-      _detected.browser = navigator.appName;
-      _detected.version = navigator.appVersion;
+    _first() {
+      const root3 = this.root;
+      if (root3 == null)
+        return null;
+      this.root = this.splayMin(root3);
+      return this.root;
     }
-    _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;
+    _last() {
+      const root3 = this.root;
+      if (root3 == null)
+        return null;
+      this.root = this.splayMax(root3);
+      return this.root;
     }
-    _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";
+    clear() {
+      this.root = null;
+      this.size = 0;
+      this.modificationCount++;
     }
-    _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 : "");
+    has(key) {
+      return this.validKey(key) && this.splay(key) == 0;
     }
-    _detected.host = origin + loc.pathname;
-    return _detected;
-  }
-
-  // modules/util/get_set_value.js
-  function utilGetSetValue(selection2, value) {
-    function d3_selection_value(value2) {
-      function valueNull() {
-        delete this.value;
+    defaultCompare() {
+      return (a2, b2) => a2 < b2 ? -1 : a2 > b2 ? 1 : 0;
+    }
+    wrap() {
+      return {
+        getRoot: () => {
+          return this.root;
+        },
+        setRoot: (root3) => {
+          this.root = root3;
+        },
+        getSize: () => {
+          return this.size;
+        },
+        getModificationCount: () => {
+          return this.modificationCount;
+        },
+        getSplayCount: () => {
+          return this.splayCount;
+        },
+        setSplayCount: (count) => {
+          this.splayCount = count;
+        },
+        splay: (key) => {
+          return this.splay(key);
+        },
+        has: (key) => {
+          return this.has(key);
+        }
+      };
+    }
+  };
+  var _a, _b;
+  var SplayTreeMap = class extends SplayTree {
+    constructor(compare2, isValidKey) {
+      super();
+      __publicField(this, "root", null);
+      __publicField(this, "compare");
+      __publicField(this, "validKey");
+      __publicField(this, _a, "[object Map]");
+      this.compare = compare2 != null ? compare2 : this.defaultCompare();
+      this.validKey = isValidKey != null ? isValidKey : (a2) => a2 != null && a2 != void 0;
+    }
+    delete(key) {
+      if (!this.validKey(key))
+        return false;
+      return this._delete(key) != null;
+    }
+    forEach(f2) {
+      const nodes = new SplayTreeMapEntryIterableIterator(this.wrap());
+      let result;
+      while (result = nodes.next(), !result.done) {
+        f2(result.value[1], result.value[0], this);
       }
-      function valueConstant() {
-        if (this.value !== value2) {
-          this.value = value2;
+    }
+    get(key) {
+      if (!this.validKey(key))
+        return void 0;
+      if (this.root != null) {
+        const comp = this.splay(key);
+        if (comp == 0) {
+          return this.root.value;
         }
       }
-      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;
+      return void 0;
+    }
+    hasValue(value) {
+      const initialSplayCount = this.splayCount;
+      const visit = (node) => {
+        while (node != null) {
+          if (node.value == value)
+            return true;
+          if (initialSplayCount != this.splayCount) {
+            throw "Concurrent modification during iteration.";
+          }
+          if (node.right != null && visit(node.right)) {
+            return true;
+          }
+          node = node.left;
         }
+        return false;
+      };
+      return visit(this.root);
+    }
+    set(key, value) {
+      const comp = this.splay(key);
+      if (comp == 0) {
+        this.root = this.root.replaceValue(value);
+        this.splayCount += 1;
+        return this;
       }
-      return value2 === null || value2 === void 0 ? valueNull : typeof value2 === "function" ? valueFunction : valueConstant;
+      this.addNewRoot(new SplayTreeMapNode(key, value), comp);
+      return this;
     }
-    if (arguments.length === 1) {
-      return selection2.property("value");
+    setAll(other) {
+      other.forEach((value, key) => {
+        this.set(key, value);
+      });
     }
-    return selection2.each(d3_selection_value(value));
-  }
+    setIfAbsent(key, ifAbsent) {
+      let comp = this.splay(key);
+      if (comp == 0) {
+        return this.root.value;
+      }
+      const modificationCount = this.modificationCount;
+      const splayCount = this.splayCount;
+      const value = ifAbsent();
+      if (modificationCount != this.modificationCount) {
+        throw "Concurrent modification during iteration.";
+      }
+      if (splayCount != this.splayCount) {
+        comp = this.splay(key);
+      }
+      this.addNewRoot(new SplayTreeMapNode(key, value), comp);
+      return value;
+    }
+    isEmpty() {
+      return this.root == null;
+    }
+    isNotEmpty() {
+      return !this.isEmpty();
+    }
+    firstKey() {
+      if (this.root == null)
+        return null;
+      return this._first().key;
+    }
+    lastKey() {
+      if (this.root == null)
+        return null;
+      return this._last().key;
+    }
+    lastKeyBefore(key) {
+      if (key == null)
+        throw "Invalid arguments(s)";
+      if (this.root == null)
+        return null;
+      const comp = this.splay(key);
+      if (comp < 0)
+        return this.root.key;
+      let node = this.root.left;
+      if (node == null)
+        return null;
+      let nodeRight = node.right;
+      while (nodeRight != null) {
+        node = nodeRight;
+        nodeRight = node.right;
+      }
+      return node.key;
+    }
+    firstKeyAfter(key) {
+      if (key == null)
+        throw "Invalid arguments(s)";
+      if (this.root == null)
+        return null;
+      const comp = this.splay(key);
+      if (comp > 0)
+        return this.root.key;
+      let node = this.root.right;
+      if (node == null)
+        return null;
+      let nodeLeft = node.left;
+      while (nodeLeft != null) {
+        node = nodeLeft;
+        nodeLeft = node.left;
+      }
+      return node.key;
+    }
+    update(key, update, ifAbsent) {
+      let comp = this.splay(key);
+      if (comp == 0) {
+        const modificationCount = this.modificationCount;
+        const splayCount = this.splayCount;
+        const newValue = update(this.root.value);
+        if (modificationCount != this.modificationCount) {
+          throw "Concurrent modification during iteration.";
+        }
+        if (splayCount != this.splayCount) {
+          this.splay(key);
+        }
+        this.root = this.root.replaceValue(newValue);
+        this.splayCount += 1;
+        return newValue;
+      }
+      if (ifAbsent != null) {
+        const modificationCount = this.modificationCount;
+        const splayCount = this.splayCount;
+        const newValue = ifAbsent();
+        if (modificationCount != this.modificationCount) {
+          throw "Concurrent modification during iteration.";
+        }
+        if (splayCount != this.splayCount) {
+          comp = this.splay(key);
+        }
+        this.addNewRoot(new SplayTreeMapNode(key, newValue), comp);
+        return newValue;
+      }
+      throw "Invalid argument (key): Key not in map.";
+    }
+    updateAll(update) {
+      const root3 = this.root;
+      if (root3 == null)
+        return;
+      const iterator = new SplayTreeMapEntryIterableIterator(this.wrap());
+      let node;
+      while (node = iterator.next(), !node.done) {
+        const newValue = update(...node.value);
+        iterator.replaceValue(newValue);
+      }
+    }
+    keys() {
+      return new SplayTreeKeyIterableIterator(this.wrap());
+    }
+    values() {
+      return new SplayTreeValueIterableIterator(this.wrap());
+    }
+    entries() {
+      return this[Symbol.iterator]();
+    }
+    [(_b = Symbol.iterator, _a = Symbol.toStringTag, _b)]() {
+      return new SplayTreeMapEntryIterableIterator(this.wrap());
+    }
+  };
+  var _a2, _b2;
+  var SplayTreeSet = class _SplayTreeSet extends SplayTree {
+    constructor(compare2, isValidKey) {
+      super();
+      __publicField(this, "root", null);
+      __publicField(this, "compare");
+      __publicField(this, "validKey");
+      __publicField(this, _a2, "[object Set]");
+      this.compare = compare2 != null ? compare2 : this.defaultCompare();
+      this.validKey = isValidKey != null ? isValidKey : (v2) => v2 != null && v2 != void 0;
+    }
+    delete(element) {
+      if (!this.validKey(element))
+        return false;
+      return this._delete(element) != null;
+    }
+    deleteAll(elements) {
+      for (const element of elements) {
+        this.delete(element);
+      }
+    }
+    forEach(f2) {
+      const nodes = this[Symbol.iterator]();
+      let result;
+      while (result = nodes.next(), !result.done) {
+        f2(result.value, result.value, this);
+      }
+    }
+    add(element) {
+      const compare2 = this.splay(element);
+      if (compare2 != 0)
+        this.addNewRoot(new SplayTreeSetNode(element), compare2);
+      return this;
+    }
+    addAndReturn(element) {
+      const compare2 = this.splay(element);
+      if (compare2 != 0)
+        this.addNewRoot(new SplayTreeSetNode(element), compare2);
+      return this.root.key;
+    }
+    addAll(elements) {
+      for (const element of elements) {
+        this.add(element);
+      }
+    }
+    isEmpty() {
+      return this.root == null;
+    }
+    isNotEmpty() {
+      return this.root != null;
+    }
+    single() {
+      if (this.size == 0)
+        throw "Bad state: No element";
+      if (this.size > 1)
+        throw "Bad state: Too many element";
+      return this.root.key;
+    }
+    first() {
+      if (this.size == 0)
+        throw "Bad state: No element";
+      return this._first().key;
+    }
+    last() {
+      if (this.size == 0)
+        throw "Bad state: No element";
+      return this._last().key;
+    }
+    lastBefore(element) {
+      if (element == null)
+        throw "Invalid arguments(s)";
+      if (this.root == null)
+        return null;
+      const comp = this.splay(element);
+      if (comp < 0)
+        return this.root.key;
+      let node = this.root.left;
+      if (node == null)
+        return null;
+      let nodeRight = node.right;
+      while (nodeRight != null) {
+        node = nodeRight;
+        nodeRight = node.right;
+      }
+      return node.key;
+    }
+    firstAfter(element) {
+      if (element == null)
+        throw "Invalid arguments(s)";
+      if (this.root == null)
+        return null;
+      const comp = this.splay(element);
+      if (comp > 0)
+        return this.root.key;
+      let node = this.root.right;
+      if (node == null)
+        return null;
+      let nodeLeft = node.left;
+      while (nodeLeft != null) {
+        node = nodeLeft;
+        nodeLeft = node.left;
+      }
+      return node.key;
+    }
+    retainAll(elements) {
+      const retainSet = new _SplayTreeSet(this.compare, this.validKey);
+      const modificationCount = this.modificationCount;
+      for (const object of elements) {
+        if (modificationCount != this.modificationCount) {
+          throw "Concurrent modification during iteration.";
+        }
+        if (this.validKey(object) && this.splay(object) == 0) {
+          retainSet.add(this.root.key);
+        }
+      }
+      if (retainSet.size != this.size) {
+        this.root = retainSet.root;
+        this.size = retainSet.size;
+        this.modificationCount++;
+      }
+    }
+    lookup(object) {
+      if (!this.validKey(object))
+        return null;
+      const comp = this.splay(object);
+      if (comp != 0)
+        return null;
+      return this.root.key;
+    }
+    intersection(other) {
+      const result = new _SplayTreeSet(this.compare, this.validKey);
+      for (const element of this) {
+        if (other.has(element))
+          result.add(element);
+      }
+      return result;
+    }
+    difference(other) {
+      const result = new _SplayTreeSet(this.compare, this.validKey);
+      for (const element of this) {
+        if (!other.has(element))
+          result.add(element);
+      }
+      return result;
+    }
+    union(other) {
+      const u2 = this.clone();
+      u2.addAll(other);
+      return u2;
+    }
+    clone() {
+      const set4 = new _SplayTreeSet(this.compare, this.validKey);
+      set4.size = this.size;
+      set4.root = this.copyNode(this.root);
+      return set4;
+    }
+    copyNode(node) {
+      if (node == null)
+        return null;
+      function copyChildren(node2, dest) {
+        let left;
+        let right;
+        do {
+          left = node2.left;
+          right = node2.right;
+          if (left != null) {
+            const newLeft = new SplayTreeSetNode(left.key);
+            dest.left = newLeft;
+            copyChildren(left, newLeft);
+          }
+          if (right != null) {
+            const newRight = new SplayTreeSetNode(right.key);
+            dest.right = newRight;
+            node2 = right;
+            dest = newRight;
+          }
+        } while (right != null);
+      }
+      const result = new SplayTreeSetNode(node.key);
+      copyChildren(node, result);
+      return result;
+    }
+    toSet() {
+      return this.clone();
+    }
+    entries() {
+      return new SplayTreeSetEntryIterableIterator(this.wrap());
+    }
+    keys() {
+      return this[Symbol.iterator]();
+    }
+    values() {
+      return this[Symbol.iterator]();
+    }
+    [(_b2 = Symbol.iterator, _a2 = Symbol.toStringTag, _b2)]() {
+      return new SplayTreeKeyIterableIterator(this.wrap());
+    }
+  };
+  var SplayTreeIterableIterator = class {
+    constructor(tree) {
+      __publicField(this, "tree");
+      __publicField(this, "path", new Array());
+      __publicField(this, "modificationCount", null);
+      __publicField(this, "splayCount");
+      this.tree = tree;
+      this.splayCount = tree.getSplayCount();
+    }
+    [Symbol.iterator]() {
+      return this;
+    }
+    next() {
+      if (this.moveNext())
+        return { done: false, value: this.current() };
+      return { done: true, value: null };
+    }
+    current() {
+      if (!this.path.length)
+        return null;
+      const node = this.path[this.path.length - 1];
+      return this.getValue(node);
+    }
+    rebuildPath(key) {
+      this.path.splice(0, this.path.length);
+      this.tree.splay(key);
+      this.path.push(this.tree.getRoot());
+      this.splayCount = this.tree.getSplayCount();
+    }
+    findLeftMostDescendent(node) {
+      while (node != null) {
+        this.path.push(node);
+        node = node.left;
+      }
+    }
+    moveNext() {
+      if (this.modificationCount != this.tree.getModificationCount()) {
+        if (this.modificationCount == null) {
+          this.modificationCount = this.tree.getModificationCount();
+          let node2 = this.tree.getRoot();
+          while (node2 != null) {
+            this.path.push(node2);
+            node2 = node2.left;
+          }
+          return this.path.length > 0;
+        }
+        throw "Concurrent modification during iteration.";
+      }
+      if (!this.path.length)
+        return false;
+      if (this.splayCount != this.tree.getSplayCount()) {
+        this.rebuildPath(this.path[this.path.length - 1].key);
+      }
+      let node = this.path[this.path.length - 1];
+      let next = node.right;
+      if (next != null) {
+        while (next != null) {
+          this.path.push(next);
+          next = next.left;
+        }
+        return true;
+      }
+      this.path.pop();
+      while (this.path.length && this.path[this.path.length - 1].right === node) {
+        node = this.path.pop();
+      }
+      return this.path.length > 0;
+    }
+  };
+  var SplayTreeKeyIterableIterator = class extends SplayTreeIterableIterator {
+    getValue(node) {
+      return node.key;
+    }
+  };
+  var SplayTreeSetEntryIterableIterator = class extends SplayTreeIterableIterator {
+    getValue(node) {
+      return [node.key, node.key];
+    }
+  };
+  var SplayTreeValueIterableIterator = class extends SplayTreeIterableIterator {
+    constructor(map2) {
+      super(map2);
+    }
+    getValue(node) {
+      return node.value;
+    }
+  };
+  var SplayTreeMapEntryIterableIterator = class extends SplayTreeIterableIterator {
+    constructor(map2) {
+      super(map2);
+    }
+    getValue(node) {
+      return [node.key, node.value];
+    }
+    replaceValue(value) {
+      if (this.modificationCount != this.tree.getModificationCount()) {
+        throw "Concurrent modification during iteration.";
+      }
+      if (this.splayCount != this.tree.getSplayCount()) {
+        this.rebuildPath(this.path[this.path.length - 1].key);
+      }
+      const last = this.path.pop();
+      const newLast = last.replaceValue(value);
+      if (!this.path.length) {
+        this.tree.setRoot(newLast);
+      } else {
+        const parent = this.path[this.path.length - 1];
+        if (last === parent.left) {
+          parent.left = newLast;
+        } else {
+          parent.right = newLast;
+        }
+      }
+      this.path.push(newLast);
+      const count = this.tree.getSplayCount() + 1;
+      this.tree.setSplayCount(count);
+      this.splayCount = count;
+    }
+  };
 
-  // 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)
+  // node_modules/polyclip-ts/dist/identity.js
+  var identity_default3 = (x2) => {
+    return x2;
+  };
+
+  // node_modules/polyclip-ts/dist/snap.js
+  var snap_default = (eps) => {
+    if (eps) {
+      const xTree = new SplayTreeSet(compare_default(eps));
+      const yTree = new SplayTreeSet(compare_default(eps));
+      const snapCoord = (coord2, tree) => {
+        return tree.addAndReturn(coord2);
+      };
+      const snap = (v2) => {
+        return {
+          x: snapCoord(v2.x, xTree),
+          y: snapCoord(v2.y, yTree)
+        };
+      };
+      snap({ x: new bignumber_default(0), y: new bignumber_default(0) });
+      return snap;
+    }
+    return identity_default3;
+  };
+
+  // node_modules/polyclip-ts/dist/precision.js
+  var set3 = (eps) => {
+    return {
+      set: (eps2) => {
+        precision = set3(eps2);
+      },
+      reset: () => set3(eps),
+      compare: compare_default(eps),
+      snap: snap_default(eps),
+      orient: orient_default(eps)
+    };
+  };
+  var precision = set3();
+
+  // node_modules/polyclip-ts/dist/bbox.js
+  var isInBbox = (bbox2, point) => {
+    return bbox2.ll.x.isLessThanOrEqualTo(point.x) && point.x.isLessThanOrEqualTo(bbox2.ur.x) && bbox2.ll.y.isLessThanOrEqualTo(point.y) && point.y.isLessThanOrEqualTo(bbox2.ur.y);
+  };
+  var getBboxOverlap = (b1, b2) => {
+    if (b2.ur.x.isLessThan(b1.ll.x) || b1.ur.x.isLessThan(b2.ll.x) || b2.ur.y.isLessThan(b1.ll.y) || b1.ur.y.isLessThan(b2.ll.y))
+      return null;
+    const lowerX = b1.ll.x.isLessThan(b2.ll.x) ? b2.ll.x : b1.ll.x;
+    const upperX = b1.ur.x.isLessThan(b2.ur.x) ? b1.ur.x : b2.ur.x;
+    const lowerY = b1.ll.y.isLessThan(b2.ll.y) ? b2.ll.y : b1.ll.y;
+    const upperY = b1.ur.y.isLessThan(b2.ur.y) ? b1.ur.y : b2.ur.y;
+    return { ll: { x: lowerX, y: lowerY }, ur: { x: upperX, y: upperY } };
+  };
+
+  // node_modules/polyclip-ts/dist/vector.js
+  var crossProduct = (a2, b2) => a2.x.times(b2.y).minus(a2.y.times(b2.x));
+  var dotProduct = (a2, b2) => a2.x.times(b2.x).plus(a2.y.times(b2.y));
+  var length = (v2) => dotProduct(v2, v2).sqrt();
+  var sineOfAngle = (pShared, pBase, pAngle) => {
+    const vBase = { x: pBase.x.minus(pShared.x), y: pBase.y.minus(pShared.y) };
+    const vAngle = { x: pAngle.x.minus(pShared.x), y: pAngle.y.minus(pShared.y) };
+    return crossProduct(vAngle, vBase).div(length(vAngle)).div(length(vBase));
+  };
+  var cosineOfAngle = (pShared, pBase, pAngle) => {
+    const vBase = { x: pBase.x.minus(pShared.x), y: pBase.y.minus(pShared.y) };
+    const vAngle = { x: pAngle.x.minus(pShared.x), y: pAngle.y.minus(pShared.y) };
+    return dotProduct(vAngle, vBase).div(length(vAngle)).div(length(vBase));
+  };
+  var horizontalIntersection = (pt2, v2, y2) => {
+    if (v2.y.isZero())
+      return null;
+    return { x: pt2.x.plus(v2.x.div(v2.y).times(y2.minus(pt2.y))), y: y2 };
+  };
+  var verticalIntersection = (pt2, v2, x2) => {
+    if (v2.x.isZero())
+      return null;
+    return { x: x2, y: pt2.y.plus(v2.y.div(v2.x).times(x2.minus(pt2.x))) };
+  };
+  var intersection = (pt1, v1, pt2, v2) => {
+    if (v1.x.isZero())
+      return verticalIntersection(pt2, v2, pt1.x);
+    if (v2.x.isZero())
+      return verticalIntersection(pt1, v1, pt2.x);
+    if (v1.y.isZero())
+      return horizontalIntersection(pt2, v2, pt1.y);
+    if (v2.y.isZero())
+      return horizontalIntersection(pt1, v1, pt2.y);
+    const kross = crossProduct(v1, v2);
+    if (kross.isZero())
+      return null;
+    const ve2 = { x: pt2.x.minus(pt1.x), y: pt2.y.minus(pt1.y) };
+    const d1 = crossProduct(ve2, v1).div(kross);
+    const d2 = crossProduct(ve2, v2).div(kross);
+    const x12 = pt1.x.plus(d2.times(v1.x)), x2 = pt2.x.plus(d1.times(v2.x));
+    const y12 = pt1.y.plus(d2.times(v1.y)), y2 = pt2.y.plus(d1.times(v2.y));
+    const x3 = x12.plus(x2).div(2);
+    const y3 = y12.plus(y2).div(2);
+    return { x: x3, y: y3 };
+  };
+
+  // node_modules/polyclip-ts/dist/sweep-event.js
+  var SweepEvent = class _SweepEvent {
+    // Warning: 'point' input will be modified and re-used (for performance)
+    constructor(point, isLeft) {
+      __publicField(this, "point");
+      __publicField(this, "isLeft");
+      __publicField(this, "segment");
+      __publicField(this, "otherSE");
+      __publicField(this, "consumedBy");
+      if (point.events === void 0)
+        point.events = [this];
+      else
+        point.events.push(this);
+      this.point = point;
+      this.isLeft = isLeft;
+    }
+    // for ordering sweep events in the sweep event queue
+    static compare(a2, b2) {
+      const ptCmp = _SweepEvent.comparePoints(a2.point, b2.point);
+      if (ptCmp !== 0)
+        return ptCmp;
+      if (a2.point !== b2.point)
+        a2.link(b2);
+      if (a2.isLeft !== b2.isLeft)
+        return a2.isLeft ? 1 : -1;
+      return Segment.compare(a2.segment, b2.segment);
+    }
+    // for ordering points in sweep line order
+    static comparePoints(aPt, bPt) {
+      if (aPt.x.isLessThan(bPt.x))
+        return -1;
+      if (aPt.x.isGreaterThan(bPt.x))
+        return 1;
+      if (aPt.y.isLessThan(bPt.y))
+        return -1;
+      if (aPt.y.isGreaterThan(bPt.y))
+        return 1;
+      return 0;
+    }
+    link(other) {
+      if (other.point === this.point) {
+        throw new Error("Tried to link already linked events");
+      }
+      const otherEvents = other.point.events;
+      for (let i3 = 0, iMax = otherEvents.length; i3 < iMax; i3++) {
+        const evt = otherEvents[i3];
+        this.point.events.push(evt);
+        evt.point = this.point;
+      }
+      this.checkForConsuming();
+    }
+    /* Do a pass over our linked events and check to see if any pair
+     * of segments match, and should be consumed. */
+    checkForConsuming() {
+      const numEvents = this.point.events.length;
+      for (let i3 = 0; i3 < numEvents; i3++) {
+        const evt1 = this.point.events[i3];
+        if (evt1.segment.consumedBy !== void 0)
           continue;
-        if (matches(d3_event, binding, true)) {
-          binding.callback(d3_event);
-          didMatch = true;
-          break;
+        for (let j2 = i3 + 1; j2 < numEvents; j2++) {
+          const evt2 = this.point.events[j2];
+          if (evt2.consumedBy !== void 0)
+            continue;
+          if (evt1.otherSE.point.events !== evt2.otherSE.point.events)
+            continue;
+          evt1.segment.consume(evt2.segment);
+        }
+      }
+    }
+    getAvailableLinkedEvents() {
+      const events = [];
+      for (let i3 = 0, iMax = this.point.events.length; i3 < iMax; i3++) {
+        const evt = this.point.events[i3];
+        if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
+          events.push(evt);
+        }
+      }
+      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.
+     */
+    getLeftmostComparator(baseEvent) {
+      const cache = /* @__PURE__ */ new Map();
+      const fillCache = (linkedEvent) => {
+        const nextEvent = linkedEvent.otherSE;
+        cache.set(linkedEvent, {
+          sine: sineOfAngle(this.point, baseEvent.point, nextEvent.point),
+          cosine: cosineOfAngle(this.point, baseEvent.point, nextEvent.point)
+        });
+      };
+      return (a2, b2) => {
+        if (!cache.has(a2))
+          fillCache(a2);
+        if (!cache.has(b2))
+          fillCache(b2);
+        const { sine: asine, cosine: acosine } = cache.get(a2);
+        const { sine: bsine, cosine: bcosine } = cache.get(b2);
+        if (asine.isGreaterThanOrEqualTo(0) && bsine.isGreaterThanOrEqualTo(0)) {
+          if (acosine.isLessThan(bcosine))
+            return 1;
+          if (acosine.isGreaterThan(bcosine))
+            return -1;
+          return 0;
+        }
+        if (asine.isLessThan(0) && bsine.isLessThan(0)) {
+          if (acosine.isLessThan(bcosine))
+            return -1;
+          if (acosine.isGreaterThan(bcosine))
+            return 1;
+          return 0;
+        }
+        if (bsine.isLessThan(asine))
+          return -1;
+        if (bsine.isGreaterThan(asine))
+          return 1;
+        return 0;
+      };
+    }
+  };
+
+  // node_modules/polyclip-ts/dist/segment.js
+  var segmentId = 0;
+  var Segment = class _Segment {
+    /* Warning: a reference to ringWindings input will be stored,
+     *  and possibly will be later modified */
+    constructor(leftSE, rightSE, rings, windings) {
+      __publicField(this, "id");
+      __publicField(this, "leftSE");
+      __publicField(this, "rightSE");
+      __publicField(this, "rings");
+      __publicField(this, "windings");
+      __publicField(this, "ringOut");
+      __publicField(this, "consumedBy");
+      __publicField(this, "prev");
+      __publicField(this, "_prevInResult");
+      __publicField(this, "_beforeState");
+      __publicField(this, "_afterState");
+      __publicField(this, "_isInResult");
+      this.id = ++segmentId;
+      this.leftSE = leftSE;
+      leftSE.segment = this;
+      leftSE.otherSE = rightSE;
+      this.rightSE = rightSE;
+      rightSE.segment = this;
+      rightSE.otherSE = leftSE;
+      this.rings = rings;
+      this.windings = windings;
+    }
+    /* 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.
+     */
+    static compare(a2, b2) {
+      const alx = a2.leftSE.point.x;
+      const blx = b2.leftSE.point.x;
+      const arx = a2.rightSE.point.x;
+      const brx = b2.rightSE.point.x;
+      if (brx.isLessThan(alx))
+        return 1;
+      if (arx.isLessThan(blx))
+        return -1;
+      const aly = a2.leftSE.point.y;
+      const bly = b2.leftSE.point.y;
+      const ary = a2.rightSE.point.y;
+      const bry = b2.rightSE.point.y;
+      if (alx.isLessThan(blx)) {
+        if (bly.isLessThan(aly) && bly.isLessThan(ary))
+          return 1;
+        if (bly.isGreaterThan(aly) && bly.isGreaterThan(ary))
+          return -1;
+        const aCmpBLeft = a2.comparePoint(b2.leftSE.point);
+        if (aCmpBLeft < 0)
+          return 1;
+        if (aCmpBLeft > 0)
+          return -1;
+        const bCmpARight = b2.comparePoint(a2.rightSE.point);
+        if (bCmpARight !== 0)
+          return bCmpARight;
+        return -1;
+      }
+      if (alx.isGreaterThan(blx)) {
+        if (aly.isLessThan(bly) && aly.isLessThan(bry))
+          return -1;
+        if (aly.isGreaterThan(bly) && aly.isGreaterThan(bry))
+          return 1;
+        const bCmpALeft = b2.comparePoint(a2.leftSE.point);
+        if (bCmpALeft !== 0)
+          return bCmpALeft;
+        const aCmpBRight = a2.comparePoint(b2.rightSE.point);
+        if (aCmpBRight < 0)
+          return 1;
+        if (aCmpBRight > 0)
+          return -1;
+        return 1;
+      }
+      if (aly.isLessThan(bly))
+        return -1;
+      if (aly.isGreaterThan(bly))
+        return 1;
+      if (arx.isLessThan(brx)) {
+        const bCmpARight = b2.comparePoint(a2.rightSE.point);
+        if (bCmpARight !== 0)
+          return bCmpARight;
+      }
+      if (arx.isGreaterThan(brx)) {
+        const aCmpBRight = a2.comparePoint(b2.rightSE.point);
+        if (aCmpBRight < 0)
+          return 1;
+        if (aCmpBRight > 0)
+          return -1;
+      }
+      if (!arx.eq(brx)) {
+        const ay = ary.minus(aly);
+        const ax = arx.minus(alx);
+        const by = bry.minus(bly);
+        const bx = brx.minus(blx);
+        if (ay.isGreaterThan(ax) && by.isLessThan(bx))
+          return 1;
+        if (ay.isLessThan(ax) && by.isGreaterThan(bx))
+          return -1;
+      }
+      if (arx.isGreaterThan(brx))
+        return 1;
+      if (arx.isLessThan(brx))
+        return -1;
+      if (ary.isLessThan(bry))
+        return -1;
+      if (ary.isGreaterThan(bry))
+        return 1;
+      if (a2.id < b2.id)
+        return -1;
+      if (a2.id > b2.id)
+        return 1;
+      return 0;
+    }
+    static fromRing(pt1, pt2, ring) {
+      let leftPt, rightPt, winding;
+      const cmpPts = SweepEvent.comparePoints(pt1, pt2);
+      if (cmpPts < 0) {
+        leftPt = pt1;
+        rightPt = pt2;
+        winding = 1;
+      } else if (cmpPts > 0) {
+        leftPt = pt2;
+        rightPt = pt1;
+        winding = -1;
+      } else
+        throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
+      const leftSE = new SweepEvent(leftPt, true);
+      const rightSE = new SweepEvent(rightPt, false);
+      return new _Segment(leftSE, rightSE, [ring], [winding]);
+    }
+    /* When a segment is split, the rightSE is replaced with a new sweep event */
+    replaceRightSE(newRightSE) {
+      this.rightSE = newRightSE;
+      this.rightSE.segment = this;
+      this.rightSE.otherSE = this.leftSE;
+      this.leftSE.otherSE = this.rightSE;
+    }
+    bbox() {
+      const y12 = this.leftSE.point.y;
+      const y2 = this.rightSE.point.y;
+      return {
+        ll: { x: this.leftSE.point.x, y: y12.isLessThan(y2) ? y12 : y2 },
+        ur: { x: this.rightSE.point.x, y: y12.isGreaterThan(y2) ? y12 : y2 }
+      };
+    }
+    /* A vector from the left point to the right */
+    vector() {
+      return {
+        x: this.rightSE.point.x.minus(this.leftSE.point.x),
+        y: this.rightSE.point.y.minus(this.leftSE.point.y)
+      };
+    }
+    isAnEndpoint(pt2) {
+      return pt2.x.eq(this.leftSE.point.x) && pt2.y.eq(this.leftSE.point.y) || pt2.x.eq(this.rightSE.point.x) && pt2.y.eq(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)
+     */
+    comparePoint(point) {
+      return precision.orient(this.leftSE.point, point, this.rightSE.point);
+    }
+    /**
+     * 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.
+     */
+    getIntersection(other) {
+      const tBbox = this.bbox();
+      const oBbox = other.bbox();
+      const bboxOverlap = getBboxOverlap(tBbox, oBbox);
+      if (bboxOverlap === null)
+        return null;
+      const tlp = this.leftSE.point;
+      const trp = this.rightSE.point;
+      const olp = other.leftSE.point;
+      const orp = other.rightSE.point;
+      const touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
+      const touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
+      const touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
+      const touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0;
+      if (touchesThisLSE && touchesOtherLSE) {
+        if (touchesThisRSE && !touchesOtherRSE)
+          return trp;
+        if (!touchesThisRSE && touchesOtherRSE)
+          return orp;
+        return null;
+      }
+      if (touchesThisLSE) {
+        if (touchesOtherRSE) {
+          if (tlp.x.eq(orp.x) && tlp.y.eq(orp.y))
+            return null;
+        }
+        return tlp;
+      }
+      if (touchesOtherLSE) {
+        if (touchesThisRSE) {
+          if (trp.x.eq(olp.x) && trp.y.eq(olp.y))
+            return null;
         }
+        return olp;
       }
-      if (didMatch)
+      if (touchesThisRSE && touchesOtherRSE)
+        return null;
+      if (touchesThisRSE)
+        return trp;
+      if (touchesOtherRSE)
+        return orp;
+      const pt2 = intersection(tlp, this.vector(), olp, other.vector());
+      if (pt2 === null)
+        return null;
+      if (!isInBbox(bboxOverlap, pt2))
+        return null;
+      return precision.snap(pt2);
+    }
+    /**
+     * 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
+     */
+    split(point) {
+      const newEvents = [];
+      const alreadyLinked = point.events !== void 0;
+      const newLeftSE = new SweepEvent(point, true);
+      const newRightSE = new SweepEvent(point, false);
+      const oldRightSE = this.rightSE;
+      this.replaceRightSE(newRightSE);
+      newEvents.push(newRightSE);
+      newEvents.push(newLeftSE);
+      const newSeg = new _Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice());
+      if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
+        newSeg.swapEvents();
+      }
+      if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
+        this.swapEvents();
+      }
+      if (alreadyLinked) {
+        newLeftSE.checkForConsuming();
+        newRightSE.checkForConsuming();
+      }
+      return newEvents;
+    }
+    /* Swap which event is left and right */
+    swapEvents() {
+      const tmpEvt = this.rightSE;
+      this.rightSE = this.leftSE;
+      this.leftSE = tmpEvt;
+      this.leftSE.isLeft = true;
+      this.rightSE.isLeft = false;
+      for (let i3 = 0, iMax = this.windings.length; i3 < iMax; i3++) {
+        this.windings[i3] *= -1;
+      }
+    }
+    /* Consume another segment. We take their rings under our wing
+     * and mark them as consumed. Use for perfectly overlapping segments */
+    consume(other) {
+      let consumer = this;
+      let consumee = other;
+      while (consumer.consumedBy)
+        consumer = consumer.consumedBy;
+      while (consumee.consumedBy)
+        consumee = consumee.consumedBy;
+      const cmp = _Segment.compare(consumer, consumee);
+      if (cmp === 0)
         return;
-      for (i2 = 0; i2 < bindings.length; i2++) {
-        binding = bindings[i2];
-        if (binding.event.modifiers.shiftKey)
+      if (cmp > 0) {
+        const tmp = consumer;
+        consumer = consumee;
+        consumee = tmp;
+      }
+      if (consumer.prev === consumee) {
+        const tmp = consumer;
+        consumer = consumee;
+        consumee = tmp;
+      }
+      for (let i3 = 0, iMax = consumee.rings.length; i3 < iMax; i3++) {
+        const ring = consumee.rings[i3];
+        const winding = consumee.windings[i3];
+        const index = consumer.rings.indexOf(ring);
+        if (index === -1) {
+          consumer.rings.push(ring);
+          consumer.windings.push(winding);
+        } else
+          consumer.windings[index] += winding;
+      }
+      consumee.rings = null;
+      consumee.windings = null;
+      consumee.consumedBy = consumer;
+      consumee.leftSE.consumedBy = consumer.leftSE;
+      consumee.rightSE.consumedBy = consumer.rightSE;
+    }
+    /* The first segment previous segment chain that is in the result */
+    prevInResult() {
+      if (this._prevInResult !== void 0)
+        return this._prevInResult;
+      if (!this.prev)
+        this._prevInResult = null;
+      else if (this.prev.isInResult())
+        this._prevInResult = this.prev;
+      else
+        this._prevInResult = this.prev.prevInResult();
+      return this._prevInResult;
+    }
+    beforeState() {
+      if (this._beforeState !== void 0)
+        return this._beforeState;
+      if (!this.prev)
+        this._beforeState = {
+          rings: [],
+          windings: [],
+          multiPolys: []
+        };
+      else {
+        const seg = this.prev.consumedBy || this.prev;
+        this._beforeState = seg.afterState();
+      }
+      return this._beforeState;
+    }
+    afterState() {
+      if (this._afterState !== void 0)
+        return this._afterState;
+      const beforeState = this.beforeState();
+      this._afterState = {
+        rings: beforeState.rings.slice(0),
+        windings: beforeState.windings.slice(0),
+        multiPolys: []
+      };
+      const ringsAfter = this._afterState.rings;
+      const windingsAfter = this._afterState.windings;
+      const mpsAfter = this._afterState.multiPolys;
+      for (let i3 = 0, iMax = this.rings.length; i3 < iMax; i3++) {
+        const ring = this.rings[i3];
+        const winding = this.windings[i3];
+        const index = ringsAfter.indexOf(ring);
+        if (index === -1) {
+          ringsAfter.push(ring);
+          windingsAfter.push(winding);
+        } else
+          windingsAfter[index] += winding;
+      }
+      const polysAfter = [];
+      const polysExclude = [];
+      for (let i3 = 0, iMax = ringsAfter.length; i3 < iMax; i3++) {
+        if (windingsAfter[i3] === 0)
           continue;
-        if (!!binding.capture !== isCapturing)
+        const ring = ringsAfter[i3];
+        const poly = ring.poly;
+        if (polysExclude.indexOf(poly) !== -1)
           continue;
-        if (matches(d3_event, binding, false)) {
-          binding.callback(d3_event);
+        if (ring.isExterior)
+          polysAfter.push(poly);
+        else {
+          if (polysExclude.indexOf(poly) === -1)
+            polysExclude.push(poly);
+          const index = polysAfter.indexOf(ring.poly);
+          if (index !== -1)
+            polysAfter.splice(index, 1);
+        }
+      }
+      for (let i3 = 0, iMax = polysAfter.length; i3 < iMax; i3++) {
+        const mp = polysAfter[i3].multiPoly;
+        if (mpsAfter.indexOf(mp) === -1)
+          mpsAfter.push(mp);
+      }
+      return this._afterState;
+    }
+    /* Is this segment part of the final result? */
+    isInResult() {
+      if (this.consumedBy)
+        return false;
+      if (this._isInResult !== void 0)
+        return this._isInResult;
+      const mpsBefore = this.beforeState().multiPolys;
+      const mpsAfter = this.afterState().multiPolys;
+      switch (operation_default.type) {
+        case "union": {
+          const noBefores = mpsBefore.length === 0;
+          const noAfters = mpsAfter.length === 0;
+          this._isInResult = noBefores !== noAfters;
           break;
         }
-      }
-      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;
-            }
+        case "intersection": {
+          let least;
+          let most;
+          if (mpsBefore.length < mpsAfter.length) {
+            least = mpsBefore.length;
+            most = mpsAfter.length;
           } else {
-            if (event.key.toLowerCase() !== binding2.event.key.toLowerCase()) {
-              isMatch = false;
-            }
+            least = mpsAfter.length;
+            most = mpsBefore.length;
           }
+          this._isInResult = most === operation_default.numMultiPolys && least < most;
+          break;
         }
-        if (!isMatch && (tryKeyCode || binding2.event.modifiers.altKey)) {
-          isMatch = event.keyCode === binding2.event.keyCode;
+        case "xor": {
+          const diff = Math.abs(mpsBefore.length - mpsAfter.length);
+          this._isInResult = diff % 2 === 1;
+          break;
         }
-        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;
+        case "difference": {
+          const isJustSubject = (mps) => mps.length === 1 && mps[0].isSubject;
+          this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
+          break;
         }
-        if (event.metaKey !== binding2.event.modifiers.metaKey)
-          return false;
-        if (testShift && event.shiftKey !== binding2.event.modifiers.shiftKey)
-          return false;
-        return true;
       }
+      return this._isInResult;
     }
-    function capture(d3_event) {
-      testBindings(d3_event, true);
+  };
+
+  // node_modules/polyclip-ts/dist/geom-in.js
+  var RingIn = class {
+    constructor(geomRing, poly, isExterior) {
+      __publicField(this, "poly");
+      __publicField(this, "isExterior");
+      __publicField(this, "segments");
+      __publicField(this, "bbox");
+      if (!Array.isArray(geomRing) || geomRing.length === 0) {
+        throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+      }
+      this.poly = poly;
+      this.isExterior = isExterior;
+      this.segments = [];
+      if (typeof geomRing[0][0] !== "number" || typeof geomRing[0][1] !== "number") {
+        throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+      }
+      const firstPoint = precision.snap({ x: new bignumber_default(geomRing[0][0]), y: new bignumber_default(geomRing[0][1]) });
+      this.bbox = {
+        ll: { x: firstPoint.x, y: firstPoint.y },
+        ur: { x: firstPoint.x, y: firstPoint.y }
+      };
+      let prevPoint = firstPoint;
+      for (let i3 = 1, iMax = geomRing.length; i3 < iMax; i3++) {
+        if (typeof geomRing[i3][0] !== "number" || typeof geomRing[i3][1] !== "number") {
+          throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+        }
+        const point = precision.snap({ x: new bignumber_default(geomRing[i3][0]), y: new bignumber_default(geomRing[i3][1]) });
+        if (point.x.eq(prevPoint.x) && point.y.eq(prevPoint.y))
+          continue;
+        this.segments.push(Segment.fromRing(prevPoint, point, this));
+        if (point.x.isLessThan(this.bbox.ll.x))
+          this.bbox.ll.x = point.x;
+        if (point.y.isLessThan(this.bbox.ll.y))
+          this.bbox.ll.y = point.y;
+        if (point.x.isGreaterThan(this.bbox.ur.x))
+          this.bbox.ur.x = point.x;
+        if (point.y.isGreaterThan(this.bbox.ur.y))
+          this.bbox.ur.y = point.y;
+        prevPoint = point;
+      }
+      if (!firstPoint.x.eq(prevPoint.x) || !firstPoint.y.eq(prevPoint.y)) {
+        this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
+      }
+    }
+    getSweepEvents() {
+      const sweepEvents = [];
+      for (let i3 = 0, iMax = this.segments.length; i3 < iMax; i3++) {
+        const segment = this.segments[i3];
+        sweepEvents.push(segment.leftSE);
+        sweepEvents.push(segment.rightSE);
+      }
+      return sweepEvents;
     }
-    function bubble(d3_event) {
-      var tagName = select_default2(d3_event.target).node().tagName;
-      if (tagName === "INPUT" || tagName === "SELECT" || tagName === "TEXTAREA") {
-        return;
+  };
+  var PolyIn = class {
+    constructor(geomPoly, multiPoly) {
+      __publicField(this, "multiPoly");
+      __publicField(this, "exteriorRing");
+      __publicField(this, "interiorRings");
+      __publicField(this, "bbox");
+      if (!Array.isArray(geomPoly)) {
+        throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
+      }
+      this.exteriorRing = new RingIn(geomPoly[0], this, true);
+      this.bbox = {
+        ll: { x: this.exteriorRing.bbox.ll.x, y: this.exteriorRing.bbox.ll.y },
+        ur: { x: this.exteriorRing.bbox.ur.x, y: this.exteriorRing.bbox.ur.y }
+      };
+      this.interiorRings = [];
+      for (let i3 = 1, iMax = geomPoly.length; i3 < iMax; i3++) {
+        const ring = new RingIn(geomPoly[i3], this, false);
+        if (ring.bbox.ll.x.isLessThan(this.bbox.ll.x))
+          this.bbox.ll.x = ring.bbox.ll.x;
+        if (ring.bbox.ll.y.isLessThan(this.bbox.ll.y))
+          this.bbox.ll.y = ring.bbox.ll.y;
+        if (ring.bbox.ur.x.isGreaterThan(this.bbox.ur.x))
+          this.bbox.ur.x = ring.bbox.ur.x;
+        if (ring.bbox.ur.y.isGreaterThan(this.bbox.ur.y))
+          this.bbox.ur.y = ring.bbox.ur.y;
+        this.interiorRings.push(ring);
+      }
+      this.multiPoly = multiPoly;
+    }
+    getSweepEvents() {
+      const sweepEvents = this.exteriorRing.getSweepEvents();
+      for (let i3 = 0, iMax = this.interiorRings.length; i3 < iMax; i3++) {
+        const ringSweepEvents = this.interiorRings[i3].getSweepEvents();
+        for (let j2 = 0, jMax = ringSweepEvents.length; j2 < jMax; j2++) {
+          sweepEvents.push(ringSweepEvents[j2]);
+        }
+      }
+      return sweepEvents;
+    }
+  };
+  var MultiPolyIn = class {
+    constructor(geom, isSubject) {
+      __publicField(this, "isSubject");
+      __publicField(this, "polys");
+      __publicField(this, "bbox");
+      if (!Array.isArray(geom)) {
+        throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
       }
-      testBindings(d3_event, false);
+      try {
+        if (typeof geom[0][0][0] === "number")
+          geom = [geom];
+      } catch (ex) {
+      }
+      this.polys = [];
+      this.bbox = {
+        ll: { x: new bignumber_default(Number.POSITIVE_INFINITY), y: new bignumber_default(Number.POSITIVE_INFINITY) },
+        ur: { x: new bignumber_default(Number.NEGATIVE_INFINITY), y: new bignumber_default(Number.NEGATIVE_INFINITY) }
+      };
+      for (let i3 = 0, iMax = geom.length; i3 < iMax; i3++) {
+        const poly = new PolyIn(geom[i3], this);
+        if (poly.bbox.ll.x.isLessThan(this.bbox.ll.x))
+          this.bbox.ll.x = poly.bbox.ll.x;
+        if (poly.bbox.ll.y.isLessThan(this.bbox.ll.y))
+          this.bbox.ll.y = poly.bbox.ll.y;
+        if (poly.bbox.ur.x.isGreaterThan(this.bbox.ur.x))
+          this.bbox.ur.x = poly.bbox.ur.x;
+        if (poly.bbox.ur.y.isGreaterThan(this.bbox.ur.y))
+          this.bbox.ur.y = poly.bbox.ur.y;
+        this.polys.push(poly);
+      }
+      this.isSubject = isSubject;
+    }
+    getSweepEvents() {
+      const sweepEvents = [];
+      for (let i3 = 0, iMax = this.polys.length; i3 < iMax; i3++) {
+        const polySweepEvents = this.polys[i3].getSweepEvents();
+        for (let j2 = 0, jMax = polySweepEvents.length; j2 < jMax; j2++) {
+          sweepEvents.push(polySweepEvents[j2]);
+        }
+      }
+      return sweepEvents;
     }
-    function keybinding(selection2) {
-      selection2 = selection2 || select_default2(document);
-      selection2.on("keydown.capture." + namespace, capture, true);
-      selection2.on("keydown.bubble." + namespace, bubble, false);
-      return keybinding;
+  };
+
+  // node_modules/polyclip-ts/dist/geom-out.js
+  var RingOut = class _RingOut {
+    constructor(events) {
+      __publicField(this, "events");
+      __publicField(this, "poly");
+      __publicField(this, "_isExteriorRing");
+      __publicField(this, "_enclosingRing");
+      this.events = events;
+      for (let i3 = 0, iMax = events.length; i3 < iMax; i3++) {
+        events[i3].segment.ringOut = this;
+      }
+      this.poly = null;
+    }
+    /* 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 */
+    static factory(allSegments) {
+      const ringsOut = [];
+      for (let i3 = 0, iMax = allSegments.length; i3 < iMax; i3++) {
+        const segment = allSegments[i3];
+        if (!segment.isInResult() || segment.ringOut)
+          continue;
+        let prevEvent = null;
+        let event = segment.leftSE;
+        let nextEvent = segment.rightSE;
+        const events = [event];
+        const startingPoint = event.point;
+        const intersectionLEs = [];
+        while (true) {
+          prevEvent = event;
+          event = nextEvent;
+          events.push(event);
+          if (event.point === startingPoint)
+            break;
+          while (true) {
+            const availableLEs = event.getAvailableLinkedEvents();
+            if (availableLEs.length === 0) {
+              const firstPt = events[0].point;
+              const lastPt = events[events.length - 1].point;
+              throw new Error("Unable to complete output ring starting at [".concat(firstPt.x, ",") + " ".concat(firstPt.y, "]. Last matching segment found ends at") + " [".concat(lastPt.x, ", ").concat(lastPt.y, "]."));
+            }
+            if (availableLEs.length === 1) {
+              nextEvent = availableLEs[0].otherSE;
+              break;
+            }
+            let indexLE = null;
+            for (let j2 = 0, jMax = intersectionLEs.length; j2 < jMax; j2++) {
+              if (intersectionLEs[j2].point === event.point) {
+                indexLE = j2;
+                break;
+              }
+            }
+            if (indexLE !== null) {
+              const intersectionLE = intersectionLEs.splice(indexLE)[0];
+              const ringEvents = events.splice(intersectionLE.index);
+              ringEvents.unshift(ringEvents[0].otherSE);
+              ringsOut.push(new _RingOut(ringEvents.reverse()));
+              continue;
+            }
+            intersectionLEs.push({
+              index: events.length,
+              point: event.point
+            });
+            const comparator = event.getLeftmostComparator(prevEvent);
+            nextEvent = availableLEs.sort(comparator)[0].otherSE;
+            break;
+          }
+        }
+        ringsOut.push(new _RingOut(events));
+      }
+      return ringsOut;
     }
-    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];
+    getGeom() {
+      let prevPt = this.events[0].point;
+      const points = [prevPt];
+      for (let i3 = 1, iMax = this.events.length - 1; i3 < iMax; i3++) {
+        const pt3 = this.events[i3].point;
+        const nextPt2 = this.events[i3 + 1].point;
+        if (precision.orient(pt3, prevPt, nextPt2) === 0)
+          continue;
+        points.push(pt3);
+        prevPt = pt3;
       }
-      return keybinding;
-    };
-    keybinding.on = function(codes, callback, capture2) {
-      if (typeof callback !== "function") {
-        return keybinding.off(codes, capture2);
+      if (points.length === 1)
+        return null;
+      const pt2 = points[0];
+      const nextPt = points[1];
+      if (precision.orient(pt2, prevPt, nextPt) === 0)
+        points.shift();
+      points.push(points[0]);
+      const step = this.isExteriorRing() ? 1 : -1;
+      const iStart = this.isExteriorRing() ? 0 : points.length - 1;
+      const iEnd = this.isExteriorRing() ? points.length : -1;
+      const orderedPoints = [];
+      for (let i3 = iStart; i3 != iEnd; i3 += step)
+        orderedPoints.push([points[i3].x.toNumber(), points[i3].y.toNumber()]);
+      return orderedPoints;
+    }
+    isExteriorRing() {
+      if (this._isExteriorRing === void 0) {
+        const enclosing = this.enclosingRing();
+        this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
+      }
+      return this._isExteriorRing;
+    }
+    enclosingRing() {
+      if (this._enclosingRing === void 0) {
+        this._enclosingRing = this._calcEnclosingRing();
+      }
+      return this._enclosingRing;
+    }
+    /* Returns the ring that encloses this one, if any */
+    _calcEnclosingRing() {
+      var _a3, _b3;
+      let leftMostEvt = this.events[0];
+      for (let i3 = 1, iMax = this.events.length; i3 < iMax; i3++) {
+        const evt = this.events[i3];
+        if (SweepEvent.compare(leftMostEvt, evt) > 0)
+          leftMostEvt = evt;
+      }
+      let prevSeg = leftMostEvt.segment.prevInResult();
+      let prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
+      while (true) {
+        if (!prevSeg)
+          return null;
+        if (!prevPrevSeg)
+          return prevSeg.ringOut;
+        if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
+          if (((_a3 = prevPrevSeg.ringOut) == null ? void 0 : _a3.enclosingRing()) !== prevSeg.ringOut) {
+            return prevSeg.ringOut;
+          } else
+            return (_b3 = prevSeg.ringOut) == null ? void 0 : _b3.enclosingRing();
+        }
+        prevSeg = prevPrevSeg.prevInResult();
+        prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
       }
-      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
+    }
+  };
+  var PolyOut = class {
+    constructor(exteriorRing) {
+      __publicField(this, "exteriorRing");
+      __publicField(this, "interiorRings");
+      this.exteriorRing = exteriorRing;
+      exteriorRing.poly = this;
+      this.interiorRings = [];
+    }
+    addInterior(ring) {
+      this.interiorRings.push(ring);
+      ring.poly = this;
+    }
+    getGeom() {
+      const geom0 = this.exteriorRing.getGeom();
+      if (geom0 === null)
+        return null;
+      const geom = [geom0];
+      for (let i3 = 0, iMax = this.interiorRings.length; i3 < iMax; i3++) {
+        const ringGeom = this.interiorRings[i3].getGeom();
+        if (ringGeom === null)
+          continue;
+        geom.push(ringGeom);
+      }
+      return geom;
+    }
+  };
+  var MultiPolyOut = class {
+    constructor(rings) {
+      __publicField(this, "rings");
+      __publicField(this, "polys");
+      this.rings = rings;
+      this.polys = this._composePolys(rings);
+    }
+    getGeom() {
+      const geom = [];
+      for (let i3 = 0, iMax = this.polys.length; i3 < iMax; i3++) {
+        const polyGeom = this.polys[i3].getGeom();
+        if (polyGeom === null)
+          continue;
+        geom.push(polyGeom);
+      }
+      return geom;
+    }
+    _composePolys(rings) {
+      var _a3;
+      const polys = [];
+      for (let i3 = 0, iMax = rings.length; i3 < iMax; i3++) {
+        const ring = rings[i3];
+        if (ring.poly)
+          continue;
+        if (ring.isExteriorRing())
+          polys.push(new PolyOut(ring));
+        else {
+          const enclosingRing = ring.enclosingRing();
+          if (!(enclosingRing == null ? void 0 : enclosingRing.poly))
+            polys.push(new PolyOut(enclosingRing));
+          (_a3 = enclosingRing == null ? void 0 : enclosingRing.poly) == null ? void 0 : _a3.addInterior(ring);
+        }
+      }
+      return polys;
+    }
+  };
+
+  // node_modules/polyclip-ts/dist/sweep-line.js
+  var SweepLine = class {
+    constructor(queue, comparator = Segment.compare) {
+      __publicField(this, "queue");
+      __publicField(this, "tree");
+      __publicField(this, "segments");
+      this.queue = queue;
+      this.tree = new SplayTreeSet(comparator);
+      this.segments = [];
+    }
+    process(event) {
+      const segment = event.segment;
+      const newEvents = [];
+      if (event.consumedBy) {
+        if (event.isLeft)
+          this.queue.delete(event.otherSE);
+        else
+          this.tree.delete(segment);
+        return newEvents;
+      }
+      if (event.isLeft)
+        this.tree.add(segment);
+      let prevSeg = segment;
+      let nextSeg = segment;
+      do {
+        prevSeg = this.tree.lastBefore(prevSeg);
+      } while (prevSeg != null && prevSeg.consumedBy != void 0);
+      do {
+        nextSeg = this.tree.firstAfter(nextSeg);
+      } while (nextSeg != null && nextSeg.consumedBy != void 0);
+      if (event.isLeft) {
+        let prevMySplitter = null;
+        if (prevSeg) {
+          const prevInter = prevSeg.getIntersection(segment);
+          if (prevInter !== null) {
+            if (!segment.isAnEndpoint(prevInter))
+              prevMySplitter = prevInter;
+            if (!prevSeg.isAnEndpoint(prevInter)) {
+              const newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
+              for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                newEvents.push(newEventsFromSplit[i3]);
+              }
             }
           }
-        };
-        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]];
+        let nextMySplitter = null;
+        if (nextSeg) {
+          const nextInter = nextSeg.getIntersection(segment);
+          if (nextInter !== null) {
+            if (!segment.isAnEndpoint(nextInter))
+              nextMySplitter = nextInter;
+            if (!nextSeg.isAnEndpoint(nextInter)) {
+              const newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
+              for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                newEvents.push(newEventsFromSplit[i3]);
+              }
+            }
+          }
+        }
+        if (prevMySplitter !== null || nextMySplitter !== null) {
+          let mySplitter = null;
+          if (prevMySplitter === null)
+            mySplitter = nextMySplitter;
+          else if (nextMySplitter === null)
+            mySplitter = prevMySplitter;
+          else {
+            const cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
+            mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
+          }
+          this.queue.delete(segment.rightSE);
+          newEvents.push(segment.rightSE);
+          const newEventsFromSplit = segment.split(mySplitter);
+          for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+            newEvents.push(newEventsFromSplit[i3]);
+          }
+        }
+        if (newEvents.length > 0) {
+          this.tree.delete(segment);
+          newEvents.push(event);
+        } else {
+          this.segments.push(segment);
+          segment.prev = prevSeg;
+        }
+      } else {
+        if (prevSeg && nextSeg) {
+          const inter = prevSeg.getIntersection(nextSeg);
+          if (inter !== null) {
+            if (!prevSeg.isAnEndpoint(inter)) {
+              const newEventsFromSplit = this._splitSafely(prevSeg, inter);
+              for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                newEvents.push(newEventsFromSplit[i3]);
+              }
+            }
+            if (!nextSeg.isAnEndpoint(inter)) {
+              const newEventsFromSplit = this._splitSafely(nextSeg, inter);
+              for (let i3 = 0, iMax = newEventsFromSplit.length; i3 < iMax; i3++) {
+                newEvents.push(newEventsFromSplit[i3]);
+              }
             }
           }
         }
+        this.tree.delete(segment);
       }
-      return keybinding;
-    };
-    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
+      return newEvents;
+    }
+    /* Safely split a segment that is currently in the datastructures
+     * IE - a segment other than the one that is currently being processed. */
+    _splitSafely(seg, pt2) {
+      this.tree.delete(seg);
+      const rightSE = seg.rightSE;
+      this.queue.delete(rightSE);
+      const newEvents = seg.split(pt2);
+      newEvents.push(rightSE);
+      if (seg.consumedBy === void 0)
+        this.tree.add(seg);
+      return newEvents;
+    }
   };
-  utilKeybinding.modifierProperties = {
-    16: "shiftKey",
-    17: "ctrlKey",
-    18: "altKey",
-    91: "metaKey"
+
+  // node_modules/polyclip-ts/dist/operation.js
+  var Operation = class {
+    constructor() {
+      __publicField(this, "type");
+      __publicField(this, "numMultiPolys");
+    }
+    run(type2, geom, moreGeoms) {
+      operation.type = type2;
+      const multipolys = [new MultiPolyIn(geom, true)];
+      for (let i3 = 0, iMax = moreGeoms.length; i3 < iMax; i3++) {
+        multipolys.push(new MultiPolyIn(moreGeoms[i3], false));
+      }
+      operation.numMultiPolys = multipolys.length;
+      if (operation.type === "difference") {
+        const subject = multipolys[0];
+        let i3 = 1;
+        while (i3 < multipolys.length) {
+          if (getBboxOverlap(multipolys[i3].bbox, subject.bbox) !== null)
+            i3++;
+          else
+            multipolys.splice(i3, 1);
+        }
+      }
+      if (operation.type === "intersection") {
+        for (let i3 = 0, iMax = multipolys.length; i3 < iMax; i3++) {
+          const mpA = multipolys[i3];
+          for (let j2 = i3 + 1, jMax = multipolys.length; j2 < jMax; j2++) {
+            if (getBboxOverlap(mpA.bbox, multipolys[j2].bbox) === null)
+              return [];
+          }
+        }
+      }
+      const queue = new SplayTreeSet(SweepEvent.compare);
+      for (let i3 = 0, iMax = multipolys.length; i3 < iMax; i3++) {
+        const sweepEvents = multipolys[i3].getSweepEvents();
+        for (let j2 = 0, jMax = sweepEvents.length; j2 < jMax; j2++) {
+          queue.add(sweepEvents[j2]);
+        }
+      }
+      const sweepLine = new SweepLine(queue);
+      let evt = null;
+      if (queue.size != 0) {
+        evt = queue.first();
+        queue.delete(evt);
+      }
+      while (evt) {
+        const newEvents = sweepLine.process(evt);
+        for (let i3 = 0, iMax = newEvents.length; i3 < iMax; i3++) {
+          const evt2 = newEvents[i3];
+          if (evt2.consumedBy === void 0)
+            queue.add(evt2);
+        }
+        if (queue.size != 0) {
+          evt = queue.first();
+          queue.delete(evt);
+        } else {
+          evt = null;
+        }
+      }
+      precision.reset();
+      const ringsOut = RingOut.factory(sweepLine.segments);
+      const result = new MultiPolyOut(ringsOut);
+      return result.getGeom();
+    }
   };
-  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;
-  }
-  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 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;
-    };
-  }
+  var operation = new Operation();
+  var operation_default = operation;
 
-  // 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";
-    }
-    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;
-    };
-    return mutex;
-  }
+  // node_modules/polyclip-ts/dist/index.js
+  var union = (geom, ...moreGeoms) => operation_default.run("union", geom, moreGeoms);
+  var difference = (geom, ...moreGeoms) => operation_default.run("difference", geom, moreGeoms);
+  var setPrecision = precision.set;
 
-  // 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/@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_geojson_precision = __toESM(require_geojson_precision(), 1);
+  var import_json_stringify_pretty_compact = __toESM(require_json_stringify_pretty_compact(), 1);
+  var LocationConflation = 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;
+      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_area.default.geometry(feature3.geometry) / 1e6;
+            props.area = Number(area.toFixed(2));
+          }
+          this._cache[id2] = feature3;
+        });
+      }
+      let world = _cloneDeep(feature("Q2"));
+      world.geometry = {
+        type: "Polygon",
+        coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
+      };
+      world.id = "Q2";
+      world.properties.id = "Q2";
+      world.properties.area = import_geojson_area.default.geometry(world.geometry) / 1e6;
+      this._cache.Q2 = world;
     }
-    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;
+    // 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];
+        const lat = location[1];
+        const radius = location[2];
+        if (Number.isFinite(lon) && lon >= -180 && lon <= 180 && Number.isFinite(lat) && lat >= -90 && lat <= 90 && (location.length === 2 || Number.isFinite(radius) && radius > 0)) {
+          const id2 = "[" + location.toString() + "]";
+          return { type: "point", location, id: id2 };
+        }
+      } else if (typeof location === "string" && /^\S+\.geojson$/i.test(location)) {
+        const id2 = location.toLowerCase();
+        if (this._cache[id2]) {
+          return { type: "geojson", location, id: id2 };
+        }
+      } else if (typeof location === "string" || typeof location === "number") {
+        const feature3 = feature(location);
+        if (feature3) {
+          const id2 = feature3.properties.wikidata;
+          return { type: "countrycoder", location, id: id2 };
+        }
+      }
+      if (this.strict) {
+        throw new Error('validateLocation:  Invalid location: "'.concat(location, '".'));
+      } else {
+        return null;
       }
-      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]);
-          }
+    // 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) return null;
+      const id2 = valid.id;
+      if (this._cache[id2]) {
+        return Object.assign(valid, { feature: this._cache[id2] });
+      }
+      if (valid.type === "point") {
+        const lon = location[0];
+        const lat = location[1];
+        const radius = location[2] || 25;
+        const EDGES = 10;
+        const PRECISION = 3;
+        const area = Math.PI * radius * radius;
+        const feature3 = this._cache[id2] = (0, import_geojson_precision.default)({
+          type: "Feature",
+          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") {
+      } else if (valid.type === "countrycoder") {
+        let feature3 = _cloneDeep(feature(id2));
+        let props = feature3.properties;
+        if (Array.isArray(props.members)) {
+          let aggregate = aggregateFeature(id2);
+          aggregate.geometry.coordinates = _clip([aggregate], "UNION").geometry.coordinates;
+          feature3.geometry = aggregate.geometry;
+        }
+        if (!props.area) {
+          const area = import_geojson_area.default.geometry(feature3.geometry) / 1e6;
+          props.area = Number(area.toFixed(2));
         }
+        feature3.id = id2;
+        props.id = id2;
+        this._cache[id2] = feature3;
+        return Object.assign(valid, { feature: feature3 });
+      }
+      if (this.strict) {
+        throw new Error("resolveLocation:  Couldn't resolve location \"".concat(location, '".'));
+      } else {
+        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;
+    // 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);
+      let include = (locationSet.include || []).map(validator).filter(Boolean);
+      let exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
+      if (!include.length) {
+        if (this.strict) {
+          throw new Error("validateLocationSet:  LocationSet includes nothing.");
+        } else {
+          locationSet.include = ["Q2"];
+          include = [{ type: "countrycoder", location: "Q2", id: "Q2" }];
         }
-        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;
+      }
+      include.sort(_sortLocations);
+      let id2 = "+[" + include.map((d2) => d2.id).join(",") + "]";
+      if (exclude.length) {
+        exclude.sort(_sortLocations);
+        id2 += "-[" + exclude.map((d2) => d2.id).join(",") + "]";
+      }
+      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);
+      if (!valid) return null;
+      const id2 = valid.id;
+      if (this._cache[id2]) {
+        return Object.assign(valid, { feature: this._cache[id2] });
+      }
+      const resolver = this.resolveLocation.bind(this);
+      const includes = (locationSet.include || []).map(resolver).filter(Boolean);
+      const excludes = (locationSet.exclude || []).map(resolver).filter(Boolean);
+      if (includes.length === 1 && excludes.length === 0) {
+        return Object.assign(valid, { feature: includes[0].feature });
+      }
+      const includeGeoJSON = _clip(includes.map((d2) => d2.feature), "UNION");
+      const excludeGeoJSON = _clip(excludes.map((d2) => d2.feature), "UNION");
+      let resultGeoJSON = excludeGeoJSON ? _clip([includeGeoJSON, excludeGeoJSON], "DIFFERENCE") : includeGeoJSON;
+      const area = import_geojson_area.default.geometry(resultGeoJSON.geometry) / 1e6;
+      resultGeoJSON.id = id2;
+      resultGeoJSON.properties = { id: id2, area: Number(area.toFixed(2)) };
+      this._cache[id2] = resultGeoJSON;
+      return Object.assign(valid, { feature: resultGeoJSON });
+    }
+    // stringify
+    // convenience method to prettyStringify the given object
+    stringify(obj, options2) {
+      return (0, import_json_stringify_pretty_compact.default)(obj, options2);
+    }
+  };
+  function _clip(features, which) {
+    if (!Array.isArray(features) || !features.length) return null;
+    const fn = { UNION: union, DIFFERENCE: difference }[which];
+    const args = features.map((feature3) => feature3.geometry.coordinates);
+    const coords = fn.apply(null, args);
+    return {
+      type: "Feature",
+      properties: {},
+      geometry: {
+        type: whichType(coords),
+        coordinates: coords
+      }
     };
-    return tiler8;
+    function whichType(coords2) {
+      const a2 = Array.isArray(coords2);
+      const b2 = a2 && Array.isArray(coords2[0]);
+      const c2 = b2 && Array.isArray(coords2[0][0]);
+      const d2 = c2 && Array.isArray(coords2[0][0][0]);
+      return d2 ? "MultiPolygon" : "Polygon";
+    }
   }
-
-  // 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);
-    });
+  function _cloneDeep(obj) {
+    return JSON.parse(JSON.stringify(obj));
+  }
+  function _sortLocations(a2, b2) {
+    const rank = { countrycoder: 1, geojson: 2, point: 3 };
+    const aRank = rank[a2.type];
+    const bRank = rank[b2.type];
+    return aRank > bRank ? 1 : aRank < bRank ? -1 : a2.id.localeCompare(b2.id);
   }
 
-  // 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;
+  // modules/core/LocationManager.js
+  var import_which_polygon2 = __toESM(require_which_polygon());
+  var import_geojson_area2 = __toESM(require_geojson_area());
+  var _loco = new LocationConflation();
+  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) {
         if (!locationSet.include) {
           locationSet.include = ["Q2"];
         }
-        const resolved = _loco.resolveLocationSet(locationSet);
-        const locationSetID = resolved.id;
+        const locationSetID = _loco.validateLocationSet(locationSet).id;
         obj.locationSetID = locationSetID;
-        if (!resolved.feature.geometry.coordinates.length || !resolved.feature.properties.area) {
-          throw new Error(`locationSet ${locationSetID} resolves to an empty feature.`);
-        }
-        if (!_resolvedFeatures[locationSetID]) {
-          let feature3 = JSON.parse(JSON.stringify(resolved.feature));
-          feature3.id = locationSetID;
-          feature3.properties.id = locationSetID;
-          _resolvedFeatures[locationSetID] = feature3;
-        }
-      } catch (err) {
+        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 s2 = this._locationIncludedIn.get(locationID);
+          if (!s2) {
+            s2 = /* @__PURE__ */ new Set();
+            this._locationIncludedIn.set(locationID, s2);
+          }
+          s2.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 s2 = this._locationExcludedIn.get(locationID);
+          if (!s2) {
+            s2 = /* @__PURE__ */ new Set();
+            this._locationExcludedIn.set(locationID, s2);
+          }
+          s2.add(locationSetID);
+        });
+        this._knownLocationSets.set(locationSetID, area);
+      } catch {
         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;
-        });
+    /**
+     * _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 ".concat(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 {
+        obj.locationSet = { include: ["Q2"] };
+        obj.locationSetID = "+[Q2]";
       }
-    };
-    _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) => {
+    }
+    /**
+     * _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) {
+      } catch {
         locationSetID = "+[Q2]";
       }
       return locationSetID;
-    };
-    _this.feature = (locationSetID) => _resolvedFeatures[locationSetID] || _resolvedFeatures["+[Q2]"];
-    _this.locationsAt = (loc) => {
+    }
+    /**
+     * 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 = {};
-      (_wp(loc, true) || []).forEach((prop) => result[prop.id] = prop.area);
+      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;
-    };
-    _this.query = (loc, multi) => _wp(loc, multi);
-    _this.loco = () => _loco;
-    _this.wp = () => _wp;
-    return _this;
-  }
+    }
+    // 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 nativeObjectToString = objectProto.toString;
   var symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0;
   function getRawTag(value) {
-    var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag];
+    var isOwn = hasOwnProperty.call(value, symToStringTag), tag2 = value[symToStringTag];
     try {
       value[symToStringTag] = void 0;
       var unmasked = true;
-    } catch (e) {
+    } catch (e3) {
     }
     var result = nativeObjectToString.call(value);
     if (unmasked) {
       if (isOwn) {
-        value[symToStringTag] = tag;
+        value[symToStringTag] = tag2;
       } else {
         delete value[symToStringTag];
       }
 
   // 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) {
+    var index = -1, length2 = array2 == null ? 0 : array2.length, result = Array(length2);
+    while (++index < length2) {
       result[index] = iteratee(array2[index], index, array2);
     }
     return result;
 
   // node_modules/lodash-es/isObject.js
   function isObject(value) {
-    var type3 = typeof value;
-    return value != null && (type3 == "object" || type3 == "function");
+    var type2 = typeof value;
+    return value != null && (type2 == "object" || type2 == "function");
   }
   var isObject_default = isObject;
 
   }
   var toNumber_default = toNumber;
 
+  // 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 tag2 = baseGetTag_default(value);
+    return tag2 == funcTag || tag2 == genTag || tag2 == asyncTag || tag2 == 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 (e3) {
+      }
+      try {
+        return func + "";
+      } catch (e3) {
+      }
+    }
+    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;
+    }
+    var pattern = isFunction_default(value) ? reIsNative : reIsHostCtor;
+    return pattern.test(toSource_default(value));
+  }
+  var baseIsNative_default = baseIsNative;
+
+  // 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_INTEGER2 = 9007199254740991;
+  var reIsUint = /^(?:0|[1-9]\d*)$/;
+  function isIndex(value, length2) {
+    var type2 = typeof value;
+    length2 = length2 == null ? MAX_SAFE_INTEGER2 : length2;
+    return !!length2 && (type2 == "number" || type2 != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length2);
+  }
+  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_INTEGER3 = 9007199254740991;
+  function isLength(value) {
+    return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER3;
+  }
+  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(n3, iteratee) {
+    var index = -1, result = Array(n3);
+    while (++index < n3) {
+      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(/* @__PURE__ */ 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;
+      }
+      return freeProcess && freeProcess.binding && freeProcess.binding("util");
+    } catch (e3) {
+    }
+  }();
+  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) : [], length2 = 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, length2)))) {
+        result.push(key);
+      }
+    }
+    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);
+    }
+    var result = [];
+    for (var key in Object(object)) {
+      if (hasOwnProperty5.call(object, key) && key != "constructor") {
+        result.push(key);
+      }
+    }
+    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, length2 = entries == null ? 0 : entries.length;
+    this.clear();
+    while (++index < length2) {
+      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 length2 = array2.length;
+    while (length2--) {
+      if (eq_default(array2[length2][0], key)) {
+        return length2;
+      }
+    }
+    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, length2 = entries == null ? 0 : entries.length;
+    this.clear();
+    while (++index < length2) {
+      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()
+    };
+  }
+  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, length2 = entries == null ? 0 : entries.length;
+    this.clear();
+    while (++index < length2) {
+      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, length2 = values.length, offset = array2.length;
+    while (++index < length2) {
+      array2[offset + index] = values[index];
+    }
+    return array2;
+  }
+  var arrayPush_default = arrayPush;
+
   // node_modules/lodash-es/_basePropertyOf.js
   function basePropertyOf(object) {
     return function(key) {
   }
   var basePropertyOf_default = basePropertyOf;
 
+  // node_modules/lodash-es/_stackClear.js
+  function stackClear() {
+    this.__data__ = new ListCache_default();
+    this.size = 0;
+  }
+  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;
+  }
+  var stackDelete_default = stackDelete;
+
+  // node_modules/lodash-es/_stackGet.js
+  function stackGet(key) {
+    return this.__data__.get(key);
+  }
+  var stackGet_default = stackGet;
+
+  // node_modules/lodash-es/_stackHas.js
+  function stackHas(key) {
+    return this.__data__.has(key);
+  }
+  var stackHas_default = stackHas;
+
+  // 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 pairs2 = data.__data__;
+      if (!Map_default || pairs2.length < LARGE_ARRAY_SIZE - 1) {
+        pairs2.push([key, value]);
+        this.size = ++data.size;
+        return this;
+      }
+      data = this.__data__ = new MapCache_default(pairs2);
+    }
+    data.set(key, value);
+    this.size = data.size;
+    return this;
+  }
+  var stackSet_default = stackSet;
+
+  // 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, length2 = array2 == null ? 0 : array2.length, resIndex = 0, result = [];
+    while (++index < length2) {
+      var value = array2[index];
+      if (predicate(value, index, array2)) {
+        result[resIndex++] = value;
+      }
+    }
+    return result;
+  }
+  var arrayFilter_default = arrayFilter;
+
+  // node_modules/lodash-es/stubArray.js
+  function stubArray() {
+    return [];
+  }
+  var stubArray_default = stubArray;
+
+  // 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 [];
+    }
+    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;
+    };
+  }
+  var getTag_default = getTag;
+
+  // 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, length2 = values == null ? 0 : values.length;
+    this.__data__ = new MapCache_default();
+    while (++index < length2) {
+      this.add(values[index]);
+    }
+  }
+  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, length2 = array2 == null ? 0 : array2.length;
+    while (++index < length2) {
+      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;
+    }
+    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;
+      }
+    }
+    stack["delete"](array2);
+    stack["delete"](other);
+    return result;
+  }
+  var equalArrays_default = equalArrays;
+
+  // 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;
+
+  // node_modules/lodash-es/_setToArray.js
+  function setToArray(set4) {
+    var index = -1, result = Array(set4.size);
+    set4.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, tag2, bitmask, customizer, equalFunc, stack) {
+    switch (tag2) {
+      case dataViewTag3:
+        if (object.byteLength != other.byteLength || object.byteOffset != other.byteOffset) {
+          return false;
+        }
+        object = object.buffer;
+        other = other.buffer;
+      case arrayBufferTag2:
+        if (object.byteLength != other.byteLength || !equalFunc(new Uint8Array_default(object), new Uint8Array_default(other))) {
+          return false;
+        }
+        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;
+        }
+        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);
+        }
+    }
+    return false;
+  }
+  var equalByTag_default = equalByTag;
+
+  // 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 index = objLength;
+    while (index--) {
+      var key = objProps[index];
+      if (!(isPartial ? key in other : hasOwnProperty8.call(other, key))) {
+        return false;
+      }
+    }
+    var objStacked = stack.get(object);
+    var othStacked = stack.get(other);
+    if (objStacked && othStacked) {
+      return objStacked == other && othStacked == object;
+    }
+    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 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 (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 (!(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);
+      }
+    }
+    if (!isSameTag) {
+      return false;
+    }
+    stack || (stack = new Stack_default());
+    return equalObjects_default(object, other, bitmask, customizer, equalFunc, stack);
+  }
+  var baseIsEqualDeep_default = baseIsEqualDeep;
+
+  // node_modules/lodash-es/_baseIsEqual.js
+  function baseIsEqual(value, other, bitmask, customizer, stack) {
+    if (value === other) {
+      return true;
+    }
+    if (value == null || other == null || !isObjectLike_default(value) && !isObjectLike_default(other)) {
+      return value !== value && other !== other;
+    }
+    return baseIsEqualDeep_default(value, other, bitmask, customizer, baseIsEqual, stack);
+  }
+  var baseIsEqual_default = baseIsEqual;
+
   // node_modules/lodash-es/now.js
   var now2 = function() {
     return root_default.Date.now();
   }
   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/isNumber.js
+  var numberTag3 = "[object Number]";
+  function isNumber(value) {
+    return typeof value == "number" || isObjectLike_default(value) && baseGetTag_default(value) == numberTag3;
+  }
+  var isNumber_default = isNumber;
+
   // node_modules/lodash-es/throttle.js
   var FUNC_ERROR_TEXT2 = "Expected a function";
   function throttle(func, wait, options2) {
   // node_modules/lodash-es/unescape.js
   var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g;
   var reHasEscapedHtml = RegExp(reEscapedHtml.source);
-  function unescape2(string) {
+  function unescape(string) {
     string = toString_default(string);
     return string && reHasEscapedHtml.test(string) ? string.replace(reEscapedHtml, unescapeHtmlChar_default) : string;
   }
-  var unescape_default = unescape2;
+  var unescape_default = unescape;
 
-  // 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;
+  // modules/util/detect.js
+  var _detected;
+  function utilDetect(refresh2) {
+    if (_detected && !refresh2) return _detected;
+    _detected = {};
+    const ua = navigator.userAgent;
+    let m2 = null;
+    m2 = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);
+    if (m2 !== null) {
+      _detected.browser = m2[1];
+      _detected.version = m2[2];
+    }
+    if (!_detected.browser) {
+      m2 = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);
+      if (m2 !== null) {
+        _detected.browser = "msie";
+        _detected.version = m2[1];
       }
-      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);
+    }
+    if (!_detected.browser) {
+      m2 = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);
+      if (m2 !== null) {
+        _detected.browser = "Opera";
+        _detected.version = m2[2];
       }
-      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);
-        }
+    }
+    if (!_detected.browser) {
+      m2 = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
+      if (m2 !== null) {
+        _detected.browser = m2[1];
+        _detected.version = m2[2];
+        m2 = ua.match(/version\/([\.\d]+)/i);
+        if (m2 !== null) _detected.version = m2[1];
       }
-      return utilArrayUniq(toUse);
     }
-    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) {
+      _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(text, key) {
+    key = key || DEFAULT_128;
+    const textBytes = import_aes_js.default.utils.utf8.toBytes(text);
+    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 text = import_aes_js.default.utils.utf8.fromBytes(decryptedBytes);
+    return text;
+  }
+
+  // modules/util/clean_tags.js
+  function utilCleanTags(tags) {
+    var out = {};
+    for (var k2 in tags) {
+      if (!k2) continue;
+      var v2 = tags[k2];
+      if (v2 !== void 0) {
+        out[k2] = cleanValue(k2, v2);
       }
-      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);
+    return out;
+    function cleanValue(k3, v3) {
+      function keepSpaces(k4) {
+        return /_hours|_times|:conditional$/.test(k4);
       }
-      let fileMap = _mainFileFetcher.fileMap();
-      const key = `locale_${scopeId}_${locale2}`;
-      if (!fileMap[key]) {
-        fileMap[key] = `${directory}/${locale2}.min.json`;
+      function skip(k4) {
+        return /^(description|note|fixme|inscription)$/.test(k4);
       }
-      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 (skip(k3)) return v3;
+      var cleaned = v3.split(";").map(function(s2) {
+        return s2.trim();
+      }).join(keepSpaces(k3) ? "; " : ";");
+      if (k3.indexOf("website") !== -1 || k3.indexOf("email") !== -1 || cleaned.indexOf("http") === 0) {
+        cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, "");
       }
-      if (number3 === 1)
-        return "one";
-      return "other";
+      return cleaned;
     }
-    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()];
+  }
+
+  // modules/util/get_set_value.js
+  function utilGetSetValue(selection2, value, shouldUpdate) {
+    function setValue(value2, shouldUpdate2) {
+      function valueNull() {
+        delete this.value;
       }
-      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
-          };
-        }
-      }
-      let index = _localeCodes.indexOf(locale2);
-      if (index >= 0 && index < _localeCodes.length - 1) {
-        let fallback = _localeCodes[index + 1];
-        return localizer.tInfo(origStringId, replacements, fallback);
-      }
-      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"
-      };
-    };
-    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;
+      function valueConstant() {
+        if (shouldUpdate2(this.value, value2)) {
+          this.value = value2;
         }
       }
-      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[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[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 x2 = value2.apply(this, arguments);
+        if (x2 === null || x2 === void 0) {
+          delete this.value;
+        } else if (shouldUpdate2(this.value, x2)) {
+          this.value = x2;
         }
       }
-      return code;
-    };
-    return localizer;
+      return value2 === null || value2 === void 0 ? valueNull : typeof value2 === "function" ? valueFunction : valueConstant;
+    }
+    if (arguments.length === 1) {
+      return selection2.property("value");
+    }
+    if (shouldUpdate === void 0) {
+      shouldUpdate = (a2, b2) => a2 !== b2;
+    }
+    return selection2.each(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]))));
-      }
-      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)));
+      var i3, binding;
+      for (i3 = 0; i3 < bindings.length; i3++) {
+        binding = bindings[i3];
+        if (!binding.event.modifiers.shiftKey) continue;
+        if (!!binding.capture !== isCapturing) continue;
+        if (matches(d3_event, binding, true)) {
+          binding.callback(d3_event);
+          didMatch = true;
+          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);
+      if (didMatch) return;
+      for (i3 = 0; i3 < bindings.length; i3++) {
+        binding = bindings[i3];
+        if (binding.event.modifiers.shiftKey) continue;
+        if (!!binding.capture !== isCapturing) continue;
+        if (matches(d3_event, binding, false)) {
+          binding.callback(d3_event);
+          break;
         }
       }
-      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;
-    };
-    _this.searchNameStripped = () => {
-      if (!_searchNameStripped) {
-        _searchNameStripped = _this.searchName();
-        if (_searchNameStripped.normalize)
-          _searchNameStripped = _searchNameStripped.normalize("NFD");
-        _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, "");
-      }
-      return _searchNameStripped;
-    };
-    _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);
-    };
-    _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;
-  }
-
-  // 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;
+      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(s2) {
+              return s2.toLowerCase();
+            }).indexOf(event.key.toLowerCase()) === -1) {
+              isMatch = false;
+            }
+          } else {
+            if (event.key.toLowerCase() !== binding2.event.key.toLowerCase()) {
+              isMatch = false;
+            }
+          }
         }
-      }
-      const addTags = _this.addTags;
-      for (let k in addTags) {
-        if (!seen[k] && entityTags[k] === addTags[k]) {
-          score += _this.originalScore;
+        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;
       }
-      if (_this.searchable === false) {
-        score *= 0.999;
-      }
-      return score;
-    };
-    _this.t = (scope, options2) => {
-      const textID = `_tagging.presets.presets.${presetID}.${scope}`;
-      return _t(textID, options2);
-    };
-    _this.t.append = (scope, options2) => {
-      const textID = `_tagging.presets.presets.${presetID}.${scope}`;
-      return _t.append(textID, options2);
-    };
-    _this.name = () => {
-      return _this.t("name", { "default": _this.originalName });
-    };
-    _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 null;
-    };
-    _this.subtitleLabel = () => {
-      if (_this.suggestion) {
-        let path = presetID.split("/");
-        path.pop();
-        return _t.append("_tagging.presets.presets." + path.join("/") + ".name");
-      }
-      return null;
-    };
-    _this.aliases = () => {
-      return _this.t("aliases", { "default": _this.originalAliases }).trim().split(/\s*[\r\n]+\s*/);
-    };
-    _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;
-    };
-    _this.searchNameStripped = () => {
-      if (!_searchNameStripped) {
-        _searchNameStripped = stripDiacritics(_this.searchName());
-      }
-      return _searchNameStripped;
-    };
-    _this.searchAliases = () => {
-      if (!_searchAliases) {
-        _searchAliases = _this.aliases().map((alias) => alias.toLowerCase());
-      }
-      return _searchAliases;
-    };
-    _this.searchAliasesStripped = () => {
-      if (!_searchAliasesStripped) {
-        _searchAliasesStripped = _this.searchAliases();
-        _searchAliasesStripped = _searchAliasesStripped.map(stripDiacritics);
+    }
+    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 _searchAliasesStripped;
-    };
-    _this.isFallback = () => {
-      const tagCount = Object.keys(_this.tags).length;
-      return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty("area");
+      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.addable = function(val) {
-      if (!arguments.length)
-        return _addable;
-      _addable = val;
-      return _this;
+    keybinding.clear = function() {
+      _keybindings = {};
+      return keybinding;
     };
-    _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 };
+    keybinding.off = function(codes, capture2) {
+      var arr = utilArrayUniq([].concat(codes));
+      for (var i3 = 0; i3 < arr.length; i3++) {
+        var id2 = arr[i3] + (capture2 ? "-capture" : "-bubble");
+        delete _keybindings[id2];
       }
+      return keybinding;
     };
-    _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];
-          }
-        });
+    keybinding.on = function(codes, callback, capture2) {
+      if (typeof callback !== "function") {
+        return keybinding.off(codes, capture2);
       }
-      delete tags.area;
-      return tags;
-    };
-    _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";
+      var arr = utilArrayUniq([].concat(codes));
+      for (var i3 = 0; i3 < arr.length; i3++) {
+        var id2 = arr[i3] + (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
+            }
           }
-        } else {
-          tags[k] = addTags[k];
+        };
+        if (_keybindings[id2]) {
+          console.warn('warning: duplicate keybinding for "' + id2 + '"');
         }
-      }
-      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;
+        _keybindings[id2] = binding;
+        var matches = arr[i3].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
+        for (var j2 = 0; j2 < matches.length; j2++) {
+          if (matches[j2] === "++") matches[j2] = "+";
+          if (matches[j2] 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]];
             }
           }
-          if (needsAreaTag) {
-            tags.area = "yes";
-          }
         }
       }
-      if (geometry && !skipFieldDefaults) {
-        _this.fields().forEach((field) => {
-          if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
-            tags[field.key] = field.default;
-          }
-        });
-      }
-      return tags;
+      return keybinding;
     };
-    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 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;
-      }
-    }
-    function stripDiacritics(s) {
-      if (s.normalize)
-        s = s.normalize("NFD");
-      s = s.replace(/[\u0300-\u036f]/g, "");
-      return s;
-    }
-    return _this;
+    return keybinding;
   }
-
-  // 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());
-      });
-    };
-    _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];
-          }
-        });
-      }
-      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 (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];
-          }
-        });
-      }
-      _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];
-          }
-        });
-      }
-      _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 (d.featureCollection && Array.isArray(d.featureCollection.features)) {
-        _mainLocations.mergeCustomGeoJSON(d.featureCollection);
-      }
-      if (newLocationSets.length) {
-        _mainLocations.mergeLocationSets(newLocationSets);
+  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 bracket, 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 bracket, 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 _this;
+      return result;
+    }, {});
+  }
+
+  // modules/util/rebind.js
+  function utilRebind(target, source) {
+    var i3 = 1, n3 = arguments.length, method;
+    while (++i3 < n3) {
+      target[method = arguments[i3]] = 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.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());
-      });
+  }
+
+  // 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.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;
-          }
-        }
-      }
-      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;
-            }
-          }
-        }
+    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;
+    };
+    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 x2 = tile[0];
+      var y2 = tile[1];
+      var z2 = tile[2];
+      if (z2 >= 7) {
+        var center = Math.pow(2, z2 - 1);
+        var width = Math.pow(2, z2 - 6);
+        var min3 = center - width / 2;
+        var max3 = center + width / 2 - 1;
+        return x2 >= min3 && x2 <= max3 && y2 >= min3 && y2 <= max3;
       }
-      if (!bestMatch || bestMatch.isFallback()) {
-        for (let k in tags) {
-          if (/^addr:/.test(k) && keyIndex["addr:*"] && keyIndex["addr:*"]["*"]) {
-            bestMatch = keyIndex["addr:*"]["*"][0];
-            break;
+      return false;
+    }
+    function tiler8() {
+      var z2 = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
+      var z0 = clamp3(Math.round(z2), _zoomExtent[0], _zoomExtent[1]);
+      var tileMin = 0;
+      var tileMax = Math.pow(2, z0) - 1;
+      var log2ts = Math.log(_tileSize) * Math.LOG2E;
+      var k2 = Math.pow(2, z2 - z0 + log2ts);
+      var origin = [
+        (_translate[0] - _scale / 2) / k2,
+        (_translate[1] - _scale / 2) / k2
+      ];
+      var cols = range(
+        clamp3(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1),
+        clamp3(Math.ceil(_size[0] / k2 - origin[0]) + _margin, tileMin, tileMax + 1)
+      );
+      var rows = range(
+        clamp3(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1),
+        clamp3(Math.ceil(_size[1] / k2 - origin[1]) + _margin, tileMin, tileMax + 1)
+      );
+      var tiles = [];
+      for (var i3 = 0; i3 < rows.length; i3++) {
+        var y2 = rows[i3];
+        for (var j2 = 0; j2 < cols.length; j2++) {
+          var x2 = cols[j2];
+          if (i3 >= _margin && i3 <= rows.length - _margin && j2 >= _margin && j2 <= cols.length - _margin) {
+            tiles.unshift([x2, y2, z0]);
+          } else {
+            tiles.push([x2, y2, z0]);
           }
         }
       }
-      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)
+      tiles.translate = origin;
+      tiles.scale = k2;
+      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;
-        return true;
-      });
-    };
-    _this.areaKeys = () => {
-      const ignore = {
-        barrier: true,
-        highway: true,
-        footway: true,
-        railway: true,
-        junction: true,
-        type: true
-      };
-      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;
+        var x2 = tile[0] * ts - origin[0];
+        var y2 = tile[1] * ts - origin[1];
+        return {
+          id: tile.toString(),
+          xyz: tile,
+          extent: geoExtent(
+            projection2.invert([x2, y2 + ts]),
+            projection2.invert([x2 + ts, y2])
+          )
+        };
+      }).filter(Boolean);
+    };
+    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 areaKeys;
+      return {
+        type: "FeatureCollection",
+        features
+      };
     };
-    _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;
-      }, {});
+    tiler8.tileSize = function(val) {
+      if (!arguments.length) return _tileSize;
+      _tileSize = val;
+      return tiler8;
     };
-    _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;
-      }, {});
+    tiler8.zoomExtent = function(val) {
+      if (!arguments.length) return _zoomExtent;
+      _zoomExtent = val;
+      return tiler8;
     };
-    _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)
-      );
-      if (Array.isArray(loc)) {
-        const validLocations = _mainLocations.locationsAt(loc);
-        result.collection = result.collection.filter((a) => !a.locationSetID || validLocations[a.locationSetID]);
-      }
-      return result;
+    tiler8.size = function(val) {
+      if (!arguments.length) return _size;
+      _size = val;
+      return tiler8;
     };
-    _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;
+    tiler8.scale = function(val) {
+      if (!arguments.length) return _scale;
+      _scale = val;
+      return tiler8;
     };
-    _this.recent = () => {
-      return presetCollection(
-        utilArrayUniq(_this.getRecents().map((d) => d.preset).filter((d) => d.searchable !== false))
-      );
+    tiler8.translate = function(val) {
+      if (!arguments.length) return _translate;
+      _translate = val;
+      return tiler8;
     };
-    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);
-      }
-      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);
+    tiler8.margin = function(val) {
+      if (!arguments.length) return _margin;
+      _margin = +val;
+      return tiler8;
     };
-    _this.removeRecent = (preset) => {
-      const item = _this.recentMatching(preset);
-      if (item) {
-        let items = _this.getRecents();
-        items.splice(items.indexOf(item), 1);
-        setRecents(items);
-      }
+    tiler8.skipNullIsland = function(val) {
+      if (!arguments.length) return _skipNullIsland;
+      _skipNullIsland = val;
+      return tiler8;
     };
-    _this.recentMatching = (preset) => {
-      const items = _this.getRecents();
-      for (let i2 in items) {
-        if (items[i2].matches(preset)) {
-          return items[i2];
-        }
+    return tiler8;
+  }
+
+  // modules/util/trigger_event.js
+  function utilTriggerEvent(target, type2, eventProperties) {
+    target.each(function() {
+      var evt = document.createEvent("HTMLEvents");
+      evt.initEvent(type2, true, true);
+      for (var prop in eventProperties) {
+        evt[prop] = eventProperties[prop];
       }
-      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);
+      this.dispatchEvent(evt);
+    });
+  }
+
+  // modules/util/units.js
+  var OSM_PRECISION = 7;
+  function displayLength(m2, isImperial) {
+    var d2 = m2 * (isImperial ? 3.28084 : 1);
+    var unit2;
+    if (isImperial) {
+      if (d2 >= 5280) {
+        d2 /= 5280;
+        unit2 = "miles";
       } else {
-        item = RibbonItem(preset, "recent");
+        unit2 = "feet";
       }
-      while (items.length >= MAXRECENTS) {
-        items.pop();
+    } else {
+      if (d2 >= 1e3) {
+        d2 /= 1e3;
+        unit2 = "kilometers";
+      } else {
+        unit2 = "meters";
       }
-      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);
+    return _t("units." + unit2, {
+      quantity: d2.toLocaleString(_mainLocalizer.localeCode(), {
+        maximumSignificantDigits: 4
+      })
+    });
+  }
+  function displayArea(m2, isImperial) {
+    var locale2 = _mainLocalizer.localeCode();
+    var d2 = m2 * (isImperial ? 10.7639111056 : 1);
+    var d1, d22, area;
+    var unit1 = "";
+    var unit2 = "";
+    if (isImperial) {
+      if (d2 >= 6969600) {
+        d1 = d2 / 27878400;
+        unit1 = "square_miles";
       } 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);
+        d1 = d2;
+        unit1 = "square_feet";
       }
-    };
-    _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;
-        }, []);
+      if (d2 > 4356 && d2 < 4356e4) {
+        d22 = d2 / 43560;
+        unit2 = "acres";
       }
-      return _favorites;
-    };
-    _this.favoriteMatching = (preset) => {
-      const favs = _this.getFavorites();
-      for (let index in favs) {
-        if (favs[index].matches(preset)) {
-          return favs[index];
-        }
+    } else {
+      if (d2 >= 25e4) {
+        d1 = d2 / 1e6;
+        unit1 = "square_kilometers";
+      } else {
+        d1 = d2;
+        unit1 = "square_meters";
       }
-      return null;
-    };
-    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));
+      if (d2 > 1e3 && d2 < 1e7) {
+        d22 = d2 / 1e4;
+        unit2 = "hectares";
       }
     }
-    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
-        });
-      }
-      if ((newVal || newVal === "") && (oldVal === void 0 || newVal !== oldVal)) {
-        tagDiff.push({
-          type: "+",
-          key: k,
-          oldVal,
-          newVal,
-          display: "+ " + k + "=" + newVal
-        });
-      }
+    area = _t("units." + unit1, {
+      quantity: d1.toLocaleString(locale2, {
+        maximumSignificantDigits: 4
+      })
     });
-    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);
+    if (d22) {
+      return _t("units.area_pair", {
+        area1: area,
+        area2: _t("units." + unit2, {
+          quantity: d22.toLocaleString(locale2, {
+            maximumSignificantDigits: 2
+          })
+        })
       });
+    } else {
+      return area;
     }
   }
-  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);
-      }
-      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);
-      } else {
-        entity.members.map(function(member) {
-          return member.id;
-        }).forEach(collectNodes);
-      }
-    }
-  }
-  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");
-        }
-      }
-    }
-    if (keyComponents.length) {
-      name = _t("inspector.display_name." + keyComponents.join("_"), tags);
-    }
-    return name;
+  function wrap(x2, min3, max3) {
+    var d2 = max3 - min3;
+    return ((x2 - min3) % d2 + d2) % d2 + min3;
   }
-  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 clamp(x2, min3, max3) {
+    return Math.max(min3, Math.min(x2, max3));
   }
-  function utilDisplayType(id2) {
-    return {
-      n: _t("inspector.node"),
-      w: _t("inspector.way"),
-      r: _t("inspector.relation")
-    }[id2.charAt(0)];
+  function roundToDecimal(target, decimalPlace) {
+    target = Number(target);
+    decimalPlace = Number(decimalPlace);
+    const factor = Math.pow(10, decimalPlace);
+    return Math.round(target * factor) / factor;
   }
-  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(" ");
+  function displayCoordinate(deg, pos, neg) {
+    var displayCoordinate2;
+    var locale2 = _mainLocalizer.localeCode();
+    var degreesFloor = Math.floor(Math.abs(deg));
+    var min3 = (Math.abs(deg) - degreesFloor) * 60;
+    var minFloor = Math.floor(min3);
+    var sec = (min3 - minFloor) * 60;
+    var fix = roundToDecimal(sec, 8);
+    var secRounded = roundToDecimal(fix, 0);
+    if (secRounded === 60) {
+      secRounded = 0;
+      minFloor += 1;
+      if (minFloor === 60) {
+        minFloor = 0;
+        degreesFloor += 1;
+      }
+    }
+    displayCoordinate2 = _t("units.arcdegrees", {
+      quantity: degreesFloor.toLocaleString(locale2)
+    }) + (minFloor !== 0 || secRounded !== 0 ? _t("units.arcminutes", {
+      quantity: minFloor.toLocaleString(locale2)
+    }) : "") + (secRounded !== 0 ? _t("units.arcseconds", {
+      quantity: secRounded.toLocaleString(locale2)
+    }) : "");
+    if (deg === 0) {
+      return displayCoordinate2;
     } else {
-      result = displayName || presetName;
+      return _t("units.coordinate", {
+        coordinate: displayCoordinate2,
+        direction: _t("units." + (deg > 0 ? pos : neg))
+      });
     }
-    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);
-      });
+  function dmsCoordinatePair(coord2) {
+    return _t("units.coordinate_pair", {
+      latitude: displayCoordinate(clamp(coord2[1], -90, 90), "north", "south"),
+      longitude: displayCoordinate(wrap(coord2[0], -180, 180), "east", "west")
     });
-    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 {
-            if (tags[key2].indexOf(value) === -1) {
-              tags[key2].push(value);
-            }
-          }
-        }
-        var tagHash = key2 + "=" + value;
-        if (!tagCounts[tagHash])
-          tagCounts[tagHash] = 0;
-        tagCounts[tagHash] += 1;
-      });
+  }
+  function decimalCoordinatePair(coord2) {
+    return _t("units.coordinate_pair", {
+      latitude: clamp(coord2[1], -90, 90).toFixed(OSM_PRECISION),
+      longitude: wrap(coord2[0], -180, 180).toFixed(OSM_PRECISION)
     });
-    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;
+  }
+  function dmsMatcher(q2) {
+    const matchers = [
+      // D M SS , D M SS  ex: 35 11 10.1 , 136 49 53.8
+      {
+        condition: /^\s*(-?)\s*(\d+)\s+(\d+)\s+(\d+\.?\d*)\s*\,\s*(-?)\s*(\d+)\s+(\d+)\s+(\d+\.?\d*)\s*$/,
+        parser: function(q3) {
+          const match = this.condition.exec(q3);
+          const lat = +match[2] + +match[3] / 60 + +match[4] / 3600;
+          const lng = +match[6] + +match[7] / 60 + +match[8] / 3600;
+          const isNegLat = match[1] === "-" ? -lat : lat;
+          const isNegLng = match[5] === "-" ? -lng : lng;
+          const d2 = [isNegLat, isNegLng];
+          return d2;
         }
-        if (val2 && val12) {
-          return val12.localeCompare(val2);
+      },
+      // D MM , D MM ex: 35 11.1683 , 136 49.8966
+      {
+        condition: /^\s*(-?)\s*(\d+)\s+(\d+\.?\d*)\s*\,\s*(-?)\s*(\d+)\s+(\d+\.?\d*)\s*$/,
+        parser: function(q3) {
+          const match = this.condition.exec(q3);
+          const lat = +match[2] + +match[3] / 60;
+          const lng = +match[5] + +match[6] / 60;
+          const isNegLat = match[1] === "-" ? -lat : lat;
+          const isNegLng = match[4] === "-" ? -lng : lng;
+          const d2 = [isNegLat, isNegLng];
+          return d2;
         }
-        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;
+    ];
+    for (const matcher of matchers) {
+      if (matcher.condition.test(q2)) {
+        return matcher.parser(q2);
       }
     }
-    return false;
+    return null;
   }
-  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();
+
+  // 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 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,
-            Math.min(
-              matrix[i2][j2 - 1] + 1,
-              matrix[i2 - 1][j2] + 1
-            )
-          );
+      return localizer;
+    };
+    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_".concat(scopeId);
+        if (!fileMap[key]) {
+          fileMap[key] = localeDirs[scopeId] + "/index.min.json";
         }
+        filesToFetch.push(key);
       }
-    }
-    return matrix[b.length][a.length];
-  }
-  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 index % length;
-  }
-  function utilFunctor(value) {
-    if (typeof value === "function")
-      return value;
-    return function() {
-      return value;
+      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, i3) => {
+          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)[i3];
+            let directory = Object.values(localeDirs)[i3];
+            if (index[code]) loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
+          });
+        });
+        return Promise.all(loadStringsPromises);
+      }).then(() => {
+        updateForCurrentLocale();
+      }).catch((err) => console.error(err));
     };
-  }
-  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;
+    function localesToUseFrom(requestedLocales) {
+      let supportedLocales = _dataLocales;
+      let toUse = [];
+      for (let i3 in requestedLocales) {
+        let locale2 = requestedLocales[i3];
+        if (supportedLocales[locale2]) toUse.push(locale2);
+        if (locale2.includes("-")) {
+          let langPart = locale2.split("-")[0];
+          if (supportedLocales[langPart]) toUse.push(langPart);
+        }
       }
+      return utilArrayUniq(toUse);
     }
-    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);
+    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 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];
+    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_".concat(scopeId, "_").concat(locale2);
+      if (!fileMap[key]) {
+        fileMap[key] = "".concat(directory, "/").concat(locale2, ".min.json");
+      }
+      return _mainFileFetcher.get(key).then((d2) => {
+        if (!_localeStrings[scopeId]) _localeStrings[scopeId] = {};
+        _localeStrings[scopeId][locale2] = d2[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 (number3 === 1) return "one";
+      return "other";
     }
-    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);
+    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((s2) => s2.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 (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];
+              }
             }
           }
-        }
-      });
-    }
-    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 (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 = "{".concat(key, "}");
+              const regex = new RegExp(token, "g");
+              result = result.replace(regex, value);
             }
           }
         }
+        if (typeof result === "string") {
+          return {
+            text: result,
+            locale: locale2
+          };
+        }
       }
-      if (!this.id && this.type) {
-        this.id = osmEntity.id(this.type);
-      }
-      if (!this.hasOwnProperty("visible")) {
-        this.visible = true;
-      }
-      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);
+      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;
-    },
-    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
-          );
-        }
+      if (replacements && "default" in replacements) {
+        return {
+          text: replacements.default,
+          locale: null
+        };
       }
-      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;
+      const missing = "Missing ".concat(locale2, " translation: ").concat(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 k2 in replacements) {
+        if (typeof replacements[k2] === "string") {
+          replacements[k2] = escape_default(replacements[k2]);
         }
-        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);
+        if (typeof replacements[k2] === "object" && typeof replacements[k2].html === "string") {
+          replacements[k2] = replacements[k2].html;
         }
-      });
-      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: []
+      }
+      const info = localizer.tInfo(stringId, replacements, locale2);
+      if (info.text) {
+        return '<span class="localized-text" lang="'.concat(info.locale || "und", '">').concat(info.text, "</span>");
+      } else {
+        return "";
+      }
     };
-    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
+    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;
     };
-  }
-  function getLaneCount(tags, isOneWay) {
-    var count;
-    if (tags.lanes) {
-      count = parseInt(tags.lanes, 10);
-      if (count > 0) {
-        return count;
+    localizer.t.addOrUpdate = function(stringId, replacements, locale2) {
+      const ret = function(selection2) {
+        const info = localizer.tInfo(stringId, replacements, locale2);
+        const span = selection2.selectAll("span.localized-text").data([info]);
+        const enter = span.enter().append("span").classed("localized-text", true);
+        span.merge(enter).attr("lang", info.locale || "und").text((replacements && replacements.prefix || "") + info.text + (replacements && replacements.suffix || ""));
+      };
+      ret.stringId = stringId;
+      return ret;
+    };
+    localizer.languageName = (code, options2) => {
+      if (_languageNames && _languageNames[code]) {
+        return _languageNames[code];
       }
-    }
-    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;
+      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 });
+          }
+        }
       }
-      forward = laneCount - bothways - backward;
-    } else if (isNaN(backward)) {
-      if (forward > laneCount - bothways) {
-        forward = laneCount - bothways;
+      return code;
+    };
+    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
+        });
       }
-      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;
-      });
-    }
+    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((_2, i3) => format2.format(i3));
+      const index = new Map(numerals.map((d2, i3) => [d2, i3]));
+      const literalPart = parts.find((d2) => d2.type === "literal");
+      const literal = literalPart && new RegExp("[".concat(literalPart.value, "]"), "g");
+      const groupPart = parts.find((d2) => d2.type === "group");
+      const group = groupPart && new RegExp("[".concat(groupPart.value, "]"), "g");
+      const decimalPart = parts.find((d2) => d2.type === "decimal");
+      const decimal = decimalPart && new RegExp("[".concat(decimalPart.value, "]"));
+      const numeral = new RegExp("[".concat(numerals.join(""), "]"), "g");
+      const getIndex = (d2) => index.get(d2);
+      return (string) => {
+        string = string.trim();
+        if (literal) string = string.replace(literal, "");
+        if (group) string = string.replace(group, "");
+        if (decimal) string = string.replace(decimal, ".");
+        string = string.replace(numeral, getIndex);
+        return string ? +string : NaN;
+      };
+    };
+    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((d2) => d2.type === "literal");
+          literal = literalPart && new RegExp("[".concat(literalPart.value, "]"), "g");
+          const groupPart = parts.find((d2) => d2.type === "group");
+          group = groupPart && new RegExp("[".concat(groupPart.value, "]"), "g");
+          const decimalPart = parts.find((d2) => d2.type === "decimal");
+          decimal = decimalPart && new RegExp("[".concat(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;
+      };
+    };
+    return localizer;
   }
 
-  // modules/osm/way.js
-  function osmWay() {
-    if (!(this instanceof osmWay)) {
-      return new osmWay().initialize(arguments);
-    } else if (arguments.length) {
-      this.initialize(arguments);
-    }
-  }
-  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;
+  // 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((d2) => d2.id === id2);
+      if (found) _memo[id2] = found;
+      return found;
+    };
+    _this.index = (id2) => _this.collection.findIndex((d2) => d2.id === id2);
+    _this.matchGeometry = (geometry) => {
+      return presetCollection(
+        _this.collection.filter((d2) => d2.matchGeometry(geometry))
+      );
+    };
+    _this.matchAllGeometry = (geometries) => {
+      return presetCollection(
+        _this.collection.filter((d2) => d2 && d2.matchAllGeometry(geometries))
+      );
+    };
+    _this.matchAnyGeometry = (geometries) => {
+      return presetCollection(
+        _this.collection.filter((d2) => geometries.some((geom) => d2.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(a2) {
+        const index = a2.indexOf(value);
+        return index === 0 || a2[index - 1] === " ";
+      }
+      function leadingStrict(a2) {
+        const index = a2.indexOf(value);
+        return index === 0;
+      }
+      function sortPresets(nameProp, aliasesProp) {
+        return function sortNames(a2, b2) {
+          let aCompare = a2[nameProp]();
+          let bCompare = b2[nameProp]();
+          if (aliasesProp) {
+            const findMatchingAlias = (strings) => {
+              if (strings.some((s2) => s2 === value)) {
+                return strings.find((s2) => s2 === value);
+              } else {
+                return strings.filter((s2) => s2.includes(value)).sort((a3, b3) => a3.length - b3.length)[0];
+              }
+            };
+            aCompare = findMatchingAlias([aCompare].concat(a2[aliasesProp]()));
+            bCompare = findMatchingAlias([bCompare].concat(b2[aliasesProp]()));
+          }
+          if (value === aCompare) return -1;
+          if (value === bCompare) return 1;
+          let i3 = b2.originalScore - a2.originalScore;
+          if (i3 !== 0) return i3;
+          i3 = aCompare.indexOf(value) - bCompare.indexOf(value);
+          if (i3 !== 0) return i3;
+          return aCompare.length - bCompare.length;
+        };
+      }
+      let pool = _this.collection;
+      if (Array.isArray(loc)) {
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        pool = pool.filter((a2) => !a2.locationSetID || validHere[a2.locationSetID]);
+      }
+      const searchable = pool.filter((a2) => a2.searchable !== false && a2.suggestion !== true);
+      const suggestions = pool.filter((a2) => a2.suggestion === true);
+      const leadingNames = searchable.filter((a2) => leading(a2.searchName()) || a2.searchAliases().some(leading)).sort(sortPresets("searchName", "searchAliases"));
+      const leadingSuggestions = suggestions.filter((a2) => leadingStrict(a2.searchName())).sort(sortPresets("searchName"));
+      const leadingNamesStripped = searchable.filter((a2) => leading(a2.searchNameStripped()) || a2.searchAliasesStripped().some(leading)).sort(sortPresets("searchNameStripped", "searchAliasesStripped"));
+      const leadingSuggestionsStripped = suggestions.filter((a2) => leadingStrict(a2.searchNameStripped())).sort(sortPresets("searchNameStripped"));
+      const leadingTerms = searchable.filter((a2) => (a2.terms() || []).some(leading));
+      const leadingSuggestionTerms = suggestions.filter((a2) => (a2.terms() || []).some(leading));
+      const leadingTagValues = searchable.filter((a2) => Object.values(a2.tags || {}).filter((val) => val !== "*").some(leading));
+      const similarName = searchable.map((a2) => ({ preset: a2, dist: utilEditDistance(value, a2.searchName()) })).filter((a2) => a2.dist + Math.min(value.length - a2.preset.searchName().length, 0) < 3).sort((a2, b2) => a2.dist - b2.dist).map((a2) => a2.preset);
+      const similarSuggestions = suggestions.map((a2) => ({ preset: a2, dist: utilEditDistance(value, a2.searchName()) })).filter((a2) => a2.dist + Math.min(value.length - a2.preset.searchName().length, 0) < 1).sort((a2, b2) => a2.dist - b2.dist).map((a2) => a2.preset);
+      const similarTerms = searchable.filter((a2) => {
+        return (a2.terms() || []).some((b2) => {
+          return utilEditDistance(value, b2) + Math.min(value.length - b2.length, 0) < 3;
+        });
       });
-    },
-    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));
+      let leadingTagKeyValues = [];
+      if (value.includes("=")) {
+        leadingTagKeyValues = searchable.filter((a2) => a2.tags && Object.keys(a2.tags).some((key) => key + "=" + a2.tags[key] === value)).concat(searchable.filter((a2) => a2.tags && Object.keys(a2.tags).some((key) => leading(key + "=" + a2.tags[key]))));
       }
-      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
+      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)));
         }
-      };
-      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 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 i3 in preset.geometry) {
+        const geometry = preset.geometry[i3];
+        if (acc.indexOf(geometry) === -1) {
+          acc.push(geometry);
         }
       }
-      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];
+      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.".concat(categoryID, ".name"), { "default": categoryID });
+    _this.nameLabel = () => _t.append("_tagging.presets.categories.".concat(categoryID, ".name"), { "default": categoryID });
+    _this.terms = () => [];
+    _this.searchName = () => {
+      if (!_searchName) {
+        _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
       }
-      for (var key in this.tags) {
-        if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) {
-          return true;
-        }
+      return _searchName;
+    };
+    _this.searchNameStripped = () => {
+      if (!_searchNameStripped) {
+        _searchNameStripped = _this.searchName();
+        if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize("NFD");
+        _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, "");
       }
-      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;
-          } else {
-            return osmRightSideIsInsideTags[key][value];
-          }
+      return _searchNameStripped;
+    };
+    _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.t = (scope, options2) => _t("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options2);
+    _this.t.html = (scope, options2) => _t.html("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options2);
+    _this.t.append = (scope, options2) => _t.append("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options2);
+    _this.hasTextForStringId = (scope) => _mainLocalizer.hasTextForStringId("_tagging.presets.fields.".concat(fieldID, ".").concat(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: ".concat(match[1]));
       }
-      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 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;
+      return _this;
+    };
+    _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 k2 in tags) {
+        seen[k2] = true;
+        if (entityTags[k2] === tags[k2]) {
+          score += _this.originalScore;
+        } else if (tags[k2] === "*" && k2 in entityTags) {
+          score += _this.originalScore / 2;
+        } else {
+          return -1;
         }
-        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;
+      const addTags = _this.addTags;
+      for (let k2 in addTags) {
+        if (!seen[k2] && entityTags[k2] === addTags[k2]) {
+          score += _this.originalScore;
         }
       }
-      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])
-          ]
-        ]);
+      if (_this.searchable === false) {
+        score *= 0.999;
       }
-      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 score;
+    };
+    _this.t = (scope, options2) => {
+      const textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
+      return _t(textID, options2);
+    };
+    _this.t.append = (scope, options2) => {
+      const textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
+      return _t.append(textID, options2);
+    };
+    function resolveReference(which) {
+      const match = (_this[which] || "").match(referenceRegex);
+      if (match) {
+        const preset2 = allPresets[match[1]];
+        if (preset2) {
+          return preset2;
         }
-        return segments;
-      });
-    },
-    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;
+        console.error("Unable to resolve referenced preset: ".concat(match[1]));
       }
-      if (index < 0 || index > max3) {
-        throw new RangeError("index " + index + " out of range 0.." + max3);
+      return _this;
+    }
+    _this.name = () => {
+      return resolveReference("originalName").t("name", { "default": _this.originalName || presetID });
+    };
+    _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");
       }
-      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;
-        }
+      return null;
+    };
+    _this.subtitleLabel = () => {
+      if (_this.suggestion) {
+        let path = presetID.split("/");
+        path.pop();
+        return _t.append("_tagging.presets.presets." + path.join("/") + ".name");
       }
-      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 null;
+    };
+    _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 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 _searchName;
+    };
+    _this.searchNameStripped = () => {
+      if (!_searchNameStripped) {
+        _searchNameStripped = stripDiacritics(_this.searchName());
       }
-      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 _searchNameStripped;
+    };
+    _this.searchAliases = () => {
+      if (!_searchAliases) {
+        _searchAliases = _this.aliases().map((alias) => alias.toLowerCase());
       }
-      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 _searchAliases;
+    };
+    _this.searchAliasesStripped = () => {
+      if (!_searchAliasesStripped) {
+        _searchAliasesStripped = _this.searchAliases();
+        _searchAliasesStripped = _searchAliasesStripped.map(stripDiacritics);
       }
-      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 _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 };
       }
-      nodes = nodes.filter(noRepeatNodes);
-      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
-        nodes.push(nodes[0]);
+      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 };
       }
-      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]);
+    };
+    _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];
+          }
+        });
       }
-      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)
+      delete tags.area;
+      return tags;
+    };
+    _this.setTags = (tags, geometry, skipFieldDefaults, loc) => {
+      const addTags = _this.addTags;
+      tags = Object.assign({}, tags);
+      for (let k2 in addTags) {
+        if (addTags[k2] === "*") {
+          if (_this.tags[k2] || !tags[k2]) {
+            tags[k2] = "yes";
+          }
+        } else {
+          tags[k2] = addTags[k2];
         }
-      };
-      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 (!addTags.hasOwnProperty("area")) {
+        delete tags.area;
+        if (geometry === "area") {
+          let needsAreaTag = true;
+          for (let k2 in addTags) {
+            if (_this.geometry.indexOf("line") === -1 && k2 in osmAreaKeys || k2 in osmAreaKeysExceptions && addTags[k2] in osmAreaKeysExceptions[k2]) {
+              needsAreaTag = false;
+              break;
+            }
+          }
+          if (needsAreaTag) {
+            tags.area = "yes";
+          }
+        }
+      }
+      if (geometry && !skipFieldDefaults) {
+        _this.fields(loc).forEach((field) => {
+          if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
+            tags[field.key] = field.default;
+          }
         });
-        if (this.isArea() && this.isClosed()) {
-          return {
-            type: "Polygon",
-            coordinates: [coordinates]
-          };
+      }
+      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 {
-          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);
+          console.log('Cannot resolve "'.concat(fieldID, '" found in ').concat(_this.id, ".").concat(which));
         }
-        return isNaN(area) ? 0 : area;
       });
-    }
-  });
-  function noRepeatNodes(node, i2, arr) {
-    return i2 === 0 || node !== arr[i2 - 1];
-  }
-
-  // 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;
+      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 == null ? void 0 : parent.locationSetID) && !validHere[parent.locationSetID]) {
+              const candidateIDs = Object.keys(allPresets).filter((k2) => k2.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 outerMember;
-  }
-  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;
-      }
-      if (member.id !== entity.id && (!member.role || member.role === "outer")) {
-        return false;
+      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 {
+          return [];
+        }
       }
-    }
-    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;
+      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;
       }
     }
-    if (!outerMember)
-      return false;
-    var outerEntity = graph.hasEntity(outerMember.id);
-    if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) {
-      return false;
+    function stripDiacritics(s2) {
+      if (s2.normalize) s2 = s2.normalize("NFD");
+      s2 = s2.replace(/[\u0300-\u036f]/g, "");
+      return s2;
     }
-    return outerEntity;
+    return _this;
   }
-  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;
+
+  // modules/presets/index.js
+  var _mainPresetIndex = presetIndex();
+  function presetIndex() {
+    const dispatch14 = 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 _defaults2 = {
+      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());
+        osmSetLineTags(_this.lineTags());
+        osmSetPointTags(_this.pointTags());
+        osmSetVertexTags(_this.vertexTags());
+      });
+    };
+    _this.merge = (d2) => {
+      let newLocationSets = [];
+      if (d2.fields) {
+        Object.keys(d2.fields).forEach((fieldID) => {
+          let f2 = d2.fields[fieldID];
+          if (f2) {
+            f2 = presetField(fieldID, f2, _fields);
+            if (f2.locationSet) newLocationSets.push(f2);
+            _fields[fieldID] = f2;
+          } else {
+            delete _fields[fieldID];
+          }
+        });
       }
-    }
-    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 (d2.presets) {
+        Object.keys(d2.presets).forEach((presetID) => {
+          let p2 = d2.presets[presetID];
+          if (p2) {
+            const isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
+            p2 = presetPreset(presetID, p2, isAddable, _fields, _presets);
+            if (p2.locationSet) newLocationSets.push(p2);
+            _presets[presetID] = p2;
+          } else {
+            const existing = _presets[presetID];
+            if (existing && !existing.isFallback()) {
+              delete _presets[presetID];
+            }
           }
-          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;
+        });
+      }
+      if (d2.categories) {
+        Object.keys(d2.categories).forEach((categoryID) => {
+          let c2 = d2.categories[categoryID];
+          if (c2) {
+            c2 = presetCategory(categoryID, c2, _presets);
+            if (c2.locationSet) newLocationSets.push(c2);
+            _categories[categoryID] = c2;
           } else {
-            fn = nodes = null;
+            delete _categories[categoryID];
           }
-        }
-        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));
+      _this.collection = Object.values(_presets).concat(Object.values(_categories));
+      if (d2.defaults) {
+        Object.keys(d2.defaults).forEach((geometry) => {
+          const def2 = d2.defaults[geometry];
+          if (Array.isArray(def2)) {
+            _defaults2[geometry] = presetCollection(
+              def2.map((id2) => _presets[id2] || _categories[id2]).filter(Boolean)
+            );
+          } else {
+            delete _defaults2[geometry];
+          }
+        });
       }
-      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);
-        }
+      _universal = Object.values(_fields).filter((field) => field.universal);
+      _geometryIndex = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
+      _this.collection.forEach((preset) => {
+        (preset.geometry || []).forEach((geometry) => {
+          let g3 = _geometryIndex[geometry];
+          for (let key in preset.tags) {
+            g3[key] = g3[key] || {};
+            let value = preset.tags[key];
+            (g3[key][value] = g3[key][value] || []).push(preset);
+          }
+        });
+      });
+      if (d2.featureCollection && Array.isArray(d2.featureCollection.features)) {
+        _sharedLocationManager.mergeCustomGeoJSON(d2.featureCollection);
       }
-      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);
+      if (newLocationSets.length) {
+        _sharedLocationManager.mergeLocationSets(newLocationSets);
       }
-      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;
-          }
+      return _this;
+    };
+    _this.match = (entity, resolver) => {
+      return resolver.transient(entity, "presetMatch", () => {
+        let geometry = entity.geometry(resolver);
+        if (geometry === "vertex" && entity.isOnAddressLine(resolver)) {
+          geometry = "point";
         }
-        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 }
-              ];
-            }
+        const entityExtent = entity.extent(resolver);
+        return _this.matchTags(entity.tags, geometry, entityExtent.center());
+      });
+    };
+    _this.matchTags = (tags, geometry, loc) => {
+      const keyIndex = _geometryIndex[geometry];
+      let bestScore = -1;
+      let bestMatch;
+      let matchCandidates = [];
+      for (let k2 in tags) {
+        let indexMatches = [];
+        let valueIndex = keyIndex[k2];
+        if (!valueIndex) continue;
+        let keyValueMatches = valueIndex[tags[k2]];
+        if (keyValueMatches) indexMatches.push(...keyValueMatches);
+        let keyStarMatches = valueIndex["*"];
+        if (keyStarMatches) indexMatches.push(...keyStarMatches);
+        if (indexMatches.length === 0) continue;
+        for (let i3 = 0; i3 < indexMatches.length; i3++) {
+          const candidate = indexMatches[i3];
+          const score = candidate.matchScore(tags);
+          if (score === -1) {
+            continue;
           }
-          if (k > 0) {
-            if (j2 + k >= members.length || item.index !== members[j2 + k].index) {
-              moveMember(members, item.index, j2 + k);
-            }
+          matchCandidates.push({ score, candidate });
+          if (score > bestScore) {
+            bestScore = score;
+            bestMatch = candidate;
           }
-          nodes.splice(0, way.nodes.length - 1);
         }
       }
-      if (tempWay) {
-        graph = graph.remove(tempWay);
-      }
-      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 (bestMatch && bestMatch.locationSetID && bestMatch.locationSetID !== "+[Q2]" && Array.isArray(loc)) {
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        if (!validHere[bestMatch.locationSetID]) {
+          matchCandidates.sort((a2, b2) => a2.score < b2.score ? 1 : -1);
+          for (let i3 = 0; i3 < matchCandidates.length; i3++) {
+            const candidateScore = matchCandidates[i3];
+            if (!candidateScore.candidate.locationSetID || validHere[candidateScore.candidate.locationSetID]) {
+              bestMatch = candidateScore.candidate;
+              bestScore = candidateScore.score;
+              break;
+            }
+          }
         }
       }
-      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) {
+      if (!bestMatch || bestMatch.isFallback()) {
+        for (let k2 in tags) {
+          if (/^addr:/.test(k2) && keyIndex["addr:*"] && keyIndex["addr:*"]["*"]) {
+            bestMatch = keyIndex["addr:*"]["*"][0];
             break;
           }
         }
-        var item2 = Object.assign({}, arr[i3]);
-        arr[i3].index = -1;
-        item2.index = toIndex;
-        arr.splice(toIndex, 0, item2);
       }
-      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 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;
+        return true;
+      });
+    };
+    _this.areaKeys = () => {
+      const ignore = {
+        barrier: true,
+        highway: true,
+        footway: true,
+        railway: true,
+        junction: true,
+        type: true
+      };
+      let areaKeys = {};
+      const presets = _this.collection.filter((p2) => !p2.suggestion && !p2.replacement);
+      presets.forEach((p2) => {
+        const keys2 = p2.tags && Object.keys(p2.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key) return;
+        if (ignore[key]) return;
+        if (p2.geometry.indexOf("area") !== -1) {
+          areaKeys[key] = areaKeys[key] || {};
         }
-        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;
+      });
+      presets.forEach((p2) => {
+        let key;
+        for (key in p2.addTags) {
+          const value = p2.addTags[key];
+          if (key in areaKeys && // probably an area...
+          p2.geometry.indexOf("line") !== -1 && // but sometimes a line
+          value !== "*") {
+            areaKeys[key][value] = true;
           }
         }
       });
-      return graph;
-    };
-  }
-
-  // modules/actions/add_vertex.js
-  function actionAddVertex(wayId, nodeId, index) {
-    return function(graph) {
-      return graph.replace(graph.entity(wayId).addNode(nodeId, index));
-    };
-  }
-
-  // modules/actions/change_member.js
-  function actionChangeMember(relationId, member, memberIndex) {
-    return function(graph) {
-      return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
+      return areaKeys;
     };
-  }
-
-  // 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 }));
+    _this.lineTags = () => {
+      return _this.collection.filter((lineTags, d2) => {
+        if (d2.suggestion || d2.replacement || d2.searchable === false) return lineTags;
+        const keys2 = d2.tags && Object.keys(d2.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key) return lineTags;
+        if (d2.geometry.indexOf("line") !== -1) {
+          lineTags[key] = lineTags[key] || [];
+          lineTags[key].push(d2.tags);
+        }
+        return lineTags;
+      }, {});
     };
-  }
-
-  // modules/actions/change_tags.js
-  function actionChangeTags(entityId, tags) {
-    return function(graph) {
-      var entity = graph.entity(entityId);
-      return graph.replace(entity.update({ tags }));
+    _this.pointTags = () => {
+      return _this.collection.reduce((pointTags, d2) => {
+        if (d2.suggestion || d2.replacement || d2.searchable === false) return pointTags;
+        const keys2 = d2.tags && Object.keys(d2.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key) return pointTags;
+        if (d2.geometry.indexOf("point") !== -1) {
+          pointTags[key] = pointTags[key] || {};
+          pointTags[key][d2.tags[key]] = true;
+        }
+        return pointTags;
+      }, {});
     };
-  }
-
-  // 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";
-      });
-    },
-    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;
-          }
+    _this.vertexTags = () => {
+      return _this.collection.reduce((vertexTags, d2) => {
+        if (d2.suggestion || d2.replacement || d2.searchable === false) return vertexTags;
+        const keys2 = d2.tags && Object.keys(d2.tags);
+        const key = keys2 && keys2.length && keys2[0];
+        if (!key) return vertexTags;
+        if (d2.geometry.indexOf("vertex") !== -1) {
+          vertexTags[key] = vertexTags[key] || {};
+          vertexTags[key][d2.tags[key]] = true;
         }
+        return vertexTags;
+      }, {});
+    };
+    _this.field = (id2) => _fields[id2];
+    _this.universal = () => _universal;
+    _this.defaults = (geometry, n3, startWithRecents, loc, extraPresets) => {
+      let recents = [];
+      if (startWithRecents) {
+        recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
       }
-      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;
-      });
-    },
-    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);
-        }
-        return false;
-      });
-    },
-    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";
+      let defaults;
+      if (_addablePresetIDs) {
+        defaults = Array.from(_addablePresetIDs).map(function(id2) {
+          var preset = _this.item(id2);
+          if (preset && preset.matchGeometry(geometry)) return preset;
+          return null;
+        }).filter(Boolean);
+      } else {
+        defaults = _defaults2[geometry].collection.concat(_this.fallback(geometry));
+      }
+      let result = presetCollection(
+        utilArrayUniq(recents.concat(defaults).concat(extraPresets || [])).slice(0, n3 - 1)
+      );
+      if (Array.isArray(loc)) {
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        result.collection = result.collection.filter((a2) => !a2.locationSetID || validHere[a2.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((p2) => {
+          if (p2.addable) p2.addable(_addablePresetIDs.has(p2.id));
         });
-      });
-    },
-    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)
-        }
-      };
-      if (changeset_id)
-        r.node["@changeset"] = changeset_id;
-      return r;
-    },
-    asGeoJSON: function() {
-      return {
-        type: "Point",
-        coordinates: this.loc
-      };
+      } else {
+        _this.collection.forEach((p2) => {
+          if (p2.addable) p2.addable(true);
+        });
+      }
+      return _this;
+    };
+    _this.recent = () => {
+      return presetCollection(
+        utilArrayUniq(_this.getRecents().map((d2) => d2.preset).filter((d2) => d2.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;
     }
-  });
-
-  // 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);
+    function ribbonItemForMinified(d2, source) {
+      if (d2 && d2.pID) {
+        const preset = _this.item(d2.pID);
+        if (!preset) return null;
+        return RibbonItem(preset, source);
       }
-      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]];
+      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((d2) => d2.minified());
+      corePreferences("preset_recents", JSON.stringify(minifiedItems));
+      dispatch14.call("recentsChange");
+    }
+    _this.getRecents = () => {
+      if (!_recents) {
+        _recents = (JSON.parse(corePreferences("preset_recents")) || []).reduce((acc, d2) => {
+          let item = ribbonItemForMinified(d2, "recent");
+          if (item && item.preset.addable()) acc.push(item);
+          return acc;
+        }, []);
       }
-      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]);
+      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);
       }
-      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);
-        }
-        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);
-            }
-          }
+    };
+    _this.recentMatching = (preset) => {
+      const items = _this.getRecents();
+      for (let i3 in items) {
+        if (items[i3].matches(preset)) {
+          return items[i3];
         }
       }
-      ids = nodes.map(function(n2) {
-        return n2.id;
-      });
-      ids.push(ids[0]);
-      way = way.update({ nodes: ids });
-      graph = graph.replace(way);
-      return graph;
+      return null;
     };
-    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();
+    _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");
       }
-      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);
-        }
+      while (items.length >= MAXRECENTS) {
+        items.pop();
       }
-      return graph;
+      items.unshift(item);
+      setRecents(items);
     };
-    action.disabled = function(graph) {
-      if (!graph.entity(wayId).isClosed()) {
-        return "not_closed";
+    function setFavorites(items) {
+      _favorites = items;
+      const minifiedItems = items.map((d2) => d2.minified());
+      corePreferences("preset_favorites", JSON.stringify(minifiedItems));
+      dispatch14.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"));
       }
-      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;
+      setFavorites(favs);
+    };
+    _this.removeFavorite = (preset) => {
+      const item = _this.favoriteMatching(preset);
+      if (item) {
+        const items = _this.getFavorites();
+        items.splice(items.indexOf(item), 1);
+        setFavorites(items);
       }
-      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;
+    };
+    _this.getFavorites = () => {
+      if (!_favorites) {
+        let rawFavorites = JSON.parse(corePreferences("preset_favorites"));
+        if (!rawFavorites) {
+          rawFavorites = [];
+          corePreferences("preset_favorites", JSON.stringify(rawFavorites));
         }
+        _favorites = rawFavorites.reduce((output, d2) => {
+          const item = ribbonItemForMinified(d2, "favorite");
+          if (item && item.preset.addable()) output.push(item);
+          return output;
+        }, []);
       }
-      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 _favorites;
+    };
+    _this.favoriteMatching = (preset) => {
+      const favs = _this.getFavorites();
+      for (let index in favs) {
+        if (favs[index].matches(preset)) {
+          return favs[index];
         }
       }
-      return "already_circular";
+      return null;
     };
-    action.transitionable = true;
-    return action;
+    return utilRebind(_this, dispatch14, "on");
   }
 
-  // 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();
+  // modules/util/util.js
+  function utilTagText(entity) {
+    var obj = entity && entity.tags || {};
+    return Object.keys(obj).map(function(k2) {
+      return k2 + "=" + obj[k2];
+    }).join(", ");
+  }
+  function utilTotalExtent(array2, graph) {
+    var extent = geoExtent();
+    var val, entity;
+    for (var i3 = 0; i3 < array2.length; i3++) {
+      val = array2[i3];
+      entity = typeof val === "string" ? graph.hasEntity(val) : val;
+      if (entity) {
+        extent._extend(entity.extent(graph));
+      }
     }
-    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);
-        }
-      });
-      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);
-    };
-    return action;
+    return extent;
   }
-
-  // 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;
+  function utilTagDiff(oldTags, newTags) {
+    var tagDiff = [];
+    var keys2 = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
+    keys2.forEach(function(k2) {
+      var oldVal = oldTags[k2];
+      var newVal = newTags[k2];
+      if ((oldVal || oldVal === "") && (newVal === void 0 || newVal !== oldVal)) {
+        tagDiff.push({
+          type: "-",
+          key: k2,
+          oldVal,
+          newVal,
+          display: "- " + k2 + "=" + oldVal
+        });
+      }
+      if ((newVal || newVal === "") && (oldVal === void 0 || newVal !== oldVal)) {
+        tagDiff.push({
+          type: "+",
+          key: k2,
+          oldVal,
+          newVal,
+          display: "+ " + k2 + "=" + newVal
+        });
+      }
+    });
+    return tagDiff;
   }
-
-  // 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);
-        }
-      });
-      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);
-        }
+  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);
       });
-      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;
+  function utilEntityOrDeepMemberSelector(ids, graph) {
+    return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
   }
-
-  // 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);
-          }
-        }
-      }
-      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));
-        }
-        parents = graph.parentRelations(node);
-        for (j2 = 0; j2 < parents.length; j2++) {
-          graph = graph.replace(parents[j2].replaceMember(node, survivor));
-        }
-        survivor = survivor.mergeTags(node.tags);
-        graph = actionDeleteNode(node.id)(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);
       }
-      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);
-        }
+      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);
+      } else {
+        entity.members.map(function(member) {
+          return member.id;
+        }).forEach(collectNodes);
       }
-      return graph;
+    }
+  }
+  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
     };
-    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;
-          }
-        }
-      }
-      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);
-            }
-          }
+    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");
         }
       }
-      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);
-        }
-        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";
+    }
+    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];
             }
-          }
-        }
-        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);
+          } else {
+            if (tags[key2].indexOf(value) === -1) {
+              tags[key2].push(value);
             }
           }
-          if (way.isDegenerate()) {
-            return "restriction";
-          }
         }
-      }
-      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] = [];
+        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 (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());
-          }
+        if (val2 && val12) {
+          return val12.localeCompare(val2);
         }
-      }
-    };
-    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);
+        return val12 ? 1 : -1;
       });
-      for (var id2 in _copies) {
-        graph = graph.replace(_copies[id2]);
+    }
+    return tags;
+  }
+  function utilStringQs(str) {
+    var i3 = 0;
+    while (i3 < str.length && (str[i3] === "?" || str[i3] === "#")) i3++;
+    str = str.slice(i3);
+    return str.split("&").reduce(function(obj, pair3) {
+      var parts = pair3.split("=");
+      if (parts.length === 2) {
+        obj[parts[0]] = null === parts[1] ? "" : decodeURIComponent(parts[1]);
       }
-      return graph;
-    };
-    action.copies = function() {
-      return _copies;
-    };
-    return action;
+      return obj;
+    }, {});
   }
-
-  // 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);
+  function utilQsString(obj, noencode) {
+    function softEncode(s2) {
+      return encodeURIComponent(s2).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 i3 = -1;
+    var n3 = prefixes2.length;
+    var s2 = document.body;
+    if (property in s2) return property;
+    property = property.slice(0, 1).toUpperCase() + property.slice(1);
+    while (++i3 < n3) {
+      if (prefixes2[i3] + property in s2) {
+        return prefixes2[i3] + property;
       }
-      return graph;
-    };
+    }
+    return false;
   }
-
-  // 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];
-          }
-        }
-        if (didDiscard) {
-          graph = graph.replace(entity.update({ tags }));
-        }
+  function utilPrefixCSSProperty(property) {
+    var prefixes2 = ["webkit", "ms", "Moz", "O"];
+    var i3 = -1;
+    var n3 = prefixes2.length;
+    var s2 = document.body.style;
+    if (property.toLowerCase() in s2) {
+      return property.toLowerCase();
+    }
+    while (++i3 < n3) {
+      if (prefixes2[i3] + property in s2) {
+        return "-" + prefixes2[i3].toLowerCase() + property.replace(/([A-Z])/g, "-$1").toLowerCase();
       }
-    };
+    }
+    return false;
   }
-
-  // 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));
-        }
-      });
-      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 });
+  var transformProperty;
+  function utilSetTransform(el, x2, y2, scale) {
+    var prop = transformProperty = transformProperty || utilPrefixCSSProperty("Transform");
+    var translate = utilDetect().opera ? "translate(" + x2 + "px," + y2 + "px)" : "translate3d(" + x2 + "px," + y2 + "px,0)";
+    return el.style(prop, translate + (scale ? " scale(" + scale + ")" : ""));
+  }
+  function utilEditDistance(a2, b2) {
+    a2 = (0, import_diacritics.remove)(a2.toLowerCase());
+    b2 = (0, import_diacritics.remove)(b2.toLowerCase());
+    if (a2.length === 0) return b2.length;
+    if (b2.length === 0) return a2.length;
+    var matrix = [];
+    var i3, j2;
+    for (i3 = 0; i3 <= b2.length; i3++) {
+      matrix[i3] = [i3];
+    }
+    for (j2 = 0; j2 <= a2.length; j2++) {
+      matrix[0][j2] = j2;
+    }
+    for (i3 = 1; i3 <= b2.length; i3++) {
+      for (j2 = 1; j2 <= a2.length; j2++) {
+        if (b2.charAt(i3 - 1) === a2.charAt(j2 - 1)) {
+          matrix[i3][j2] = matrix[i3 - 1][j2 - 1];
         } 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 });
-            }
-          }
+          matrix[i3][j2] = Math.min(
+            matrix[i3 - 1][j2 - 1] + 1,
+            // substitution
+            Math.min(
+              matrix[i3][j2 - 1] + 1,
+              // insertion
+              matrix[i3 - 1][j2] + 1
+            )
+          );
         }
       }
-      return keeping ? candidates : candidates.slice(1);
+    }
+    return matrix[b2.length][a2.length];
+  }
+  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(e3) {
+      return [
+        e3.clientX - rectLeft - clientLeft,
+        e3.clientY - rectTop - clientTop
+      ];
     };
-    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;
-          }
-        });
+  }
+  function utilAsyncMap(inputs, func, callback) {
+    var remaining = inputs.length;
+    var results = [];
+    var errors = [];
+    inputs.forEach(function(d2, i3) {
+      func(d2, function done(err, data) {
+        errors[i3] = err;
+        results[i3] = data;
+        remaining--;
+        if (!remaining) callback(errors, results);
       });
-      if (sharedRelation)
-        return "relation";
-    };
-    action.limitWays = function(val) {
-      if (!arguments.length)
-        return wayIds;
-      wayIds = val;
-      return action;
+    });
+  }
+  function utilWrap(index, length2) {
+    if (index < 0) {
+      index += Math.ceil(-index / length2) * length2;
+    }
+    return index % length2;
+  }
+  function utilFunctor(value) {
+    if (typeof value === "function") return value;
+    return function() {
+      return value;
     };
-    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 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(str) {
+    var hash = 0;
+    if (str.length === 0) {
+      return hash;
     }
-    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;
-        }
-        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 }));
+    for (var i3 = 0; i3 < str.length; i3++) {
+      var char = str.charCodeAt(i3);
+      hash = (hash << 5) - hash + char;
+      hash = hash & hash;
     }
-    action.getExtractedNodeID = function() {
-      return extractedNodeID;
-    };
-    return action;
+    return hash;
   }
-
-  // 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 utilSafeClassName(str) {
+    return str.toLowerCase().replace(/[^a-z0-9]+/g, "_");
+  }
+  function utilUniqueDomId(val) {
+    return "ideditor-" + utilSafeClassName(val.toString()) + "-" + (/* @__PURE__ */ new Date()).getTime().toString();
+  }
+  function utilUnicodeCharsCount(str) {
+    return Array.from(str).length;
+  }
+  function utilUnicodeCharsTruncated(str, limit) {
+    return Array.from(str).slice(0, limit).join("");
+  }
+  function toNumericID(id2) {
+    var match = id2.match(/^[cnwr](-?\d+)$/);
+    if (match) {
+      return parseInt(match[1], 10);
     }
-    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] && 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";
-        }
-        delete tags.type;
-        survivor = survivor.update({ tags });
-        graph = graph.replace(survivor);
-      }
-      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 joined = osmJoinWays(ids.map(graph.entity, graph), graph);
-      if (joined.length > 1) {
-        return "not_adjacent";
-      }
-      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 < 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 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;
-          }
-        }
-      });
-      if (relation) {
-        return relation.isRestriction() ? "restriction" : "connectivity";
-      }
-      if (conflicting) {
-        return "conflicting_tags";
-      }
-    };
-    return action;
+    return NaN;
   }
-
-  // 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);
-        })
-      );
+  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 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;
-            }
-          }
-          if (!inserted && point.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(point.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.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";
+    var oldestIDIndex = 0;
+    var oldestID = toNumericID(ids[0]);
+    for (var i3 = 1; i3 < ids.length; i3++) {
+      var num = toNumericID(ids[i3]);
+      if (compareNumericIDs(oldestID, num) === 1) {
+        oldestIDIndex = i3;
+        oldestID = num;
       }
-    };
-    return action;
+    }
+    return ids[oldestIDIndex];
   }
-
-  // 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);
+  function utilCleanOsmString(val, maxChars) {
+    if (val === void 0 || val === null) {
+      val = "";
+    } else {
+      val = val.toString();
     }
-    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 actionConnect(nodeIDs)(graph);
-    };
-    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;
+    val = val.trim();
+    if (val.normalize) val = val.normalize("NFC");
+    return utilUnicodeCharsTruncated(val, maxChars);
   }
 
-  // modules/osm/changeset.js
-  function osmChangeset() {
-    if (!(this instanceof osmChangeset)) {
-      return new osmChangeset().initialize(arguments);
-    } else if (arguments.length) {
-      this.initialize(arguments);
+  // 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.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"
-          }
-        }
-      };
-    },
-    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;
-      }
-      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();
+  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];
+    }
+    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(d2) {
+        var oldKeys = Object.keys(d2.old);
+        if (oldKeys.length === 1) {
+          var oldKey = oldKeys[0];
+          var oldValue = d2.old[oldKey];
+          if (oldValue !== "*") {
+            if (!_deprecatedTagValuesByKey[oldKey]) {
+              _deprecatedTagValuesByKey[oldKey] = [oldValue];
             } else {
-              processing = deps.concat(processing);
+              _deprecatedTagValuesByKey[oldKey].push(oldValue);
             }
           }
         }
-        changes2.relation = Object.values(sorted);
-        return changes2;
-      }
-      function rep2(entity) {
-        return entity.asJXON(changeset_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 })
-        }
-      };
-    },
-    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--;
+    return _deprecatedTagValuesByKey;
   };
-  osmNote.id.next = -1;
-  Object.assign(osmNote.prototype, {
-    type: "note",
+  osmEntity.prototype = {
+    tags: {},
     initialize: function(sources) {
-      for (var i2 = 0; i2 < sources.length; ++i2) {
-        var source = sources[i2];
+      for (var i3 = 0; i3 < sources.length; ++i3) {
+        var source = sources[i3];
         for (var prop in source) {
           if (Object.prototype.hasOwnProperty.call(source, prop)) {
             if (source[prop] === void 0) {
           }
         }
       }
-      if (!this.id) {
-        this.id = osmNote.id().toString();
+      if (!this.id && this.type) {
+        this.id = osmEntity.id(this.type);
+      }
+      if (!this.hasOwnProperty("visible")) {
+        this.visible = true;
+      }
+      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);
       }
       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 });
+      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;
     },
-    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));
-          }
-        }
-        return extent;
-      });
+    osmId: function() {
+      return osmEntity.id.toOSM(this.id);
     },
-    geometry: function(graph) {
-      return graph.transient(this, "geometry", function() {
-        return this.isMultipolygon() ? "area" : "relation";
-      });
-    },
-    isDegenerate: function() {
-      return this.members.length === 0;
+    isNew: function() {
+      var osmId = osmEntity.id.toOSM(this.id);
+      return osmId.length === 0 || osmId[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 });
-      }
-      return result;
+    update: function(attrs) {
+      return osmEntity(this, attrs, { v: 1 + (this.v || 0) });
     },
-    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 });
+    mergeTags: function(tags) {
+      var merged = Object.assign({}, this.tags);
+      var changed = false;
+      for (var k2 in tags) {
+        var t1 = merged[k2];
+        var t2 = tags[k2];
+        if (!t1) {
+          changed = true;
+          merged[k2] = t2;
+        } else if (t1 !== t2) {
+          changed = true;
+          merged[k2] = utilUnicodeCharsTruncated(
+            utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(";"),
+            255
+            // avoid exceeding character limit; see also context.maxCharsForTagValue()
+          );
         }
       }
+      return changed ? this.update({ tags: merged }) : this;
     },
-    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;
+    intersects: function(extent, resolver) {
+      return this.extent(resolver).intersects(extent);
     },
-    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 });
+    hasNonGeometryTags: function() {
+      return Object.keys(this.tags).some(function(k2) {
+        return k2 !== "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(d2) {
+        var oldKeys = Object.keys(d2.old);
+        if (d2.replace) {
+          var hasExistingValues = Object.keys(d2.replace).some(function(replaceKey) {
+            if (!tags[replaceKey] || d2.old[replaceKey]) return false;
+            var replaceValue = d2.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 (d2.old[oldKey] === "*") return true;
+          if (d2.old[oldKey] === tags[oldKey]) return true;
+          var vals = tags[oldKey].split(";").filter(Boolean);
+          if (vals.length === 0) {
+            return false;
+          } else if (vals.length > 1) {
+            return vals.indexOf(d2.old[oldKey]) !== -1;
+          } else {
+            if (tags[oldKey] === d2.old[oldKey]) {
+              if (d2.replace && d2.old[oldKey] === d2.replace[oldKey]) {
+                var replaceKeys = Object.keys(d2.replace);
+                return !replaceKeys.every(function(replaceKey) {
+                  return tags[replaceKey] === d2.replace[replaceKey];
+                });
+              } else {
+                return true;
+              }
+            }
+          }
+          return false;
+        });
+        if (matchesDeprecatedTags) {
+          deprecated.push(d2);
         }
+      });
+      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: []
+    };
+    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
+    };
+  }
+  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;
+      }
+      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(tag2) {
+    if (!tag2) return;
+    var validValues = [
+      "left",
+      "slight_left",
+      "sharp_left",
+      "through",
+      "right",
+      "slight_right",
+      "sharp_right",
+      "reverse",
+      "merge_to_left",
+      "merge_to_right",
+      "none"
+    ];
+    return tag2.split("|").map(function(s2) {
+      if (s2 === "") s2 = "none";
+      return s2.split(";").map(function(d2) {
+        return validValues.indexOf(d2) === -1 ? "unknown" : d2;
+      });
+    });
+  }
+  function parseMaxspeedLanes(tag2, maxspeed) {
+    if (!tag2) return;
+    return tag2.split("|").map(function(s2) {
+      if (s2 === "none") return s2;
+      var m2 = parseInt(s2, 10);
+      if (s2 === "" || m2 === maxspeed) return null;
+      return isNaN(m2) ? "unknown" : m2;
+    });
+  }
+  function parseMiscLanes(tag2) {
+    if (!tag2) return;
+    var validValues = [
+      "yes",
+      "no",
+      "designated"
+    ];
+    return tag2.split("|").map(function(s2) {
+      if (s2 === "") s2 = "no";
+      return validValues.indexOf(s2) === -1 ? "unknown" : s2;
+    });
+  }
+  function parseBicycleWay(tag2) {
+    if (!tag2) return;
+    var validValues = [
+      "yes",
+      "no",
+      "designated",
+      "lane"
+    ];
+    return tag2.split("|").map(function(s2) {
+      if (s2 === "") s2 = "no";
+      return validValues.indexOf(s2) === -1 ? "unknown" : s2;
+    });
+  }
+  function mapToLanesObj(lanesObj, data, key) {
+    if (data.forward) {
+      data.forward.forEach(function(l2, i3) {
+        if (!lanesObj.forward[i3]) lanesObj.forward[i3] = {};
+        lanesObj.forward[i3][key] = l2;
+      });
+    }
+    if (data.backward) {
+      data.backward.forEach(function(l2, i3) {
+        if (!lanesObj.backward[i3]) lanesObj.backward[i3] = {};
+        lanesObj.backward[i3][key] = l2;
+      });
+    }
+    if (data.unspecified) {
+      data.unspecified.forEach(function(l2, i3) {
+        if (!lanesObj.unspecified[i3]) lanesObj.unspecified[i3] = {};
+        lanesObj.unspecified[i3][key] = l2;
+      });
+    }
+  }
+
+  // modules/osm/way.js
+  function osmWay() {
+    if (!(this instanceof osmWay)) {
+      return new osmWay().initialize(arguments);
+    } else if (arguments.length) {
+      this.initialize(arguments);
+    }
+  }
+  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;
     },
-    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 });
+    extent: function(resolver) {
+      return resolver.transient(this, "extent", function() {
+        var extent = geoExtent();
+        for (var i3 = 0; i3 < this.nodes.length; i3++) {
+          var node = resolver.hasEntity(this.nodes[i3]);
+          if (node) {
+            extent._extend(node.extent());
+          }
         }
-      }
+        return extent;
+      });
     },
-    addMember: function(member, index) {
-      var members = this.members.slice();
-      members.splice(index === void 0 ? members.length : index, 0, member);
-      return this.update({ members });
+    first: function() {
+      return this.nodes[0];
     },
-    updateMember: function(member, index) {
-      var members = this.members.slice();
-      members.splice(index, 1, Object.assign({}, members[index], member));
-      return this.update({ members });
+    last: function() {
+      return this.nodes[this.nodes.length - 1];
     },
-    removeMember: function(index) {
-      var members = this.members.slice();
-      members.splice(index, 1);
-      return this.update({ members });
+    contains: function(node) {
+      return this.nodes.indexOf(node) >= 0;
     },
-    removeMembersWithID: function(id2) {
-      var members = this.members.filter(function(m) {
-        return m.id !== id2;
-      });
-      return this.update({ members });
+    affix: function(node) {
+      if (this.nodes[0] === node) return "prefix";
+      if (this.nodes[this.nodes.length - 1] === node) return "suffix";
     },
-    moveMember: function(fromIndex, toIndex) {
-      var members = this.members.slice();
-      members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
-      return this.update({ members });
+    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;
     },
-    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 });
+    // 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,
+          busway: 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,
+          ladder: 0.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
+        }
+      };
+      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 this.update({ members });
+      return null;
     },
-    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)
-        }
+    isOneWay: function() {
+      var values = {
+        "yes": true,
+        "1": true,
+        "-1": true,
+        "reversible": true,
+        "alternating": true,
+        "no": false,
+        "0": false
       };
-      if (changeset_id) {
-        r.relation["@changeset"] = changeset_id;
+      if (values[this.tags.oneway] !== void 0) {
+        return values[this.tags.oneway];
       }
-      return r;
+      for (var key in this.tags) {
+        if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) {
+          return true;
+        }
+      }
+      return false;
     },
-    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));
-            })
-          };
+    // 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];
+          }
         }
-      });
+      }
+      return null;
     },
-    area: function(resolver) {
-      return resolver.transient(this, "area", function() {
-        return area_default(this.asGeoJSON(resolver));
-      });
+    isSided: function() {
+      if (this.tags.two_sided === "yes") {
+        return false;
+      }
+      return this.sidednessIdentifier() !== null;
     },
-    isMultipolygon: function() {
-      return this.tags.type === "multipolygon";
+    lanes: function() {
+      return osmLanes(this);
     },
-    isComplete: function(resolver) {
-      for (var i2 = 0; i2 < this.members.length; i2++) {
-        if (!resolver.hasEntity(this.members[i2].id)) {
+    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(n3) {
+        return n3.loc;
+      });
+      var curr = 0;
+      var prev = 0;
+      for (var i3 = 0; i3 < coords.length; i3++) {
+        var o2 = coords[(i3 + 1) % coords.length];
+        var a2 = coords[i3];
+        var b2 = coords[(i3 + 2) % coords.length];
+        var res = geoVecCross(a2, b2, o2);
+        curr = res > 0 ? 1 : res < 0 ? -1 : 0;
+        if (curr === 0) {
+          continue;
+        } else if (prev && curr !== prev) {
           return false;
         }
+        prev = curr;
       }
       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:?/));
+    // returns an object with the tag that implies this is an area, if any
+    tagSuggestingArea: function() {
+      return osmTagSuggestingArea(this.tags);
     },
-    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;
+    isArea: function() {
+      if (this.tags.area === "yes") return true;
+      if (!this.isClosed() || this.tags.area === "no") return false;
+      return this.tagSuggestingArea() !== null;
     },
-    isConnectivity: function() {
-      return !!(this.tags.type && this.tags.type.match(/^connectivity:?/));
+    isDegenerate: function() {
+      return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
     },
-    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]);
+    areAdjacent: function(n1, n22) {
+      for (var i3 = 0; i3 < this.nodes.length; i3++) {
+        if (this.nodes[i3] === n1) {
+          if (this.nodes[i3 - 1] === n22) return true;
+          if (this.nodes[i3 + 1] === n22) return true;
         }
-        return sequence.nodes.map(function(node) {
-          return node.loc;
-        });
-      };
-      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];
+      }
+      return false;
+    },
+    geometry: function(graph) {
+      return graph.transient(this, "geometry", function() {
+        return this.isArea() ? "area" : "line";
       });
-      function findOuter(inner2) {
-        var o2, outer;
-        for (o2 = 0; o2 < outers.length; o2++) {
-          outer = outers[o2];
-          if (geoPolygonContainsPolygon(outer, inner2)) {
-            return o2;
-          }
-        }
-        for (o2 = 0; o2 < outers.length; o2++) {
-          outer = outers[o2];
-          if (geoPolygonIntersectsPolygon(outer, inner2, false)) {
-            return o2;
-          }
+    },
+    // 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 n22 = graph2.hasEntity(this.nodes[1]);
+        return n1 && n22 && geoExtent([
+          [
+            Math.min(n1.loc[0], n22.loc[0]),
+            Math.min(n1.loc[1], n22.loc[1])
+          ],
+          [
+            Math.max(n1.loc[0], n22.loc[0]),
+            Math.max(n1.loc[1], n22.loc[1])
+          ]
+        ]);
+      }
+      return graph.transient(this, "segments", function() {
+        var segments = [];
+        for (var i3 = 0; i3 < this.nodes.length - 1; i3++) {
+          segments.push({
+            id: this.id + "-" + i3,
+            wayId: this.id,
+            index: i3,
+            nodes: [this.nodes[i3], this.nodes[i3 + 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 i3 = nodes.length - 1;
+      while (i3 > 0 && nodes.length > 1 && nodes[i3] === connector) {
+        nodes.splice(i3, 1);
+        i3 = nodes.length - 1;
       }
-      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();
+      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 i3 = 1;
+        while (i3 < nodes.length && nodes.length > 2 && nodes[i3] === connector) {
+          nodes.splice(i3, 1);
+          if (index > i3) index--;
         }
-        var o = findOuter(inners[i2]);
-        if (o !== void 0) {
-          result[o].push(inners[i2]);
-        } else {
-          result.push([inners[i2]]);
+        i3 = nodes.length - 1;
+        while (i3 > 0 && nodes.length > 1 && nodes[i3] === connector) {
+          nodes.splice(i3, 1);
+          if (index > i3) index--;
+          i3 = nodes.length - 1;
         }
       }
-      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);
-      }
-    }
-    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;
-
-  // 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);
+      nodes.splice(index, 0, id2);
+      nodes = nodes.filter(noRepeatNodes);
+      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
+        nodes.push(nodes[0]);
       }
-      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;
+      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);
       }
-      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 (isClosed) {
+        var connector = this.first();
+        var i3 = 1;
+        while (i3 < nodes.length && nodes.length > 2 && nodes[i3] === connector) {
+          nodes.splice(i3, 1);
+          if (index > i3) index--;
         }
-      }
-      for (i2 = 0; i2 < nodes.length; i2++) {
-        var cost = lengths[i2] / dist(graph, nodes[idxA], nodes[i2]);
-        if (cost > best) {
-          idxB = i2;
-          best = cost;
+        i3 = nodes.length - 1;
+        while (i3 > 0 && nodes.length > 1 && nodes[i3] === connector) {
+          nodes.splice(i3, 1);
+          if (index === i3) index = 0;
+          i3 = nodes.length - 1;
         }
       }
-      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]);
+      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 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));
+      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 i3 = 0; i3 < nodes.length; i3++) {
+        if (nodes[i3] === needleID) {
+          nodes[i3] = replacementID;
         }
-      } 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 });
+      nodes = nodes.filter(noRepeatNodes);
+      if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
+        nodes.push(nodes[0]);
       }
-      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 });
+      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 r2 = {
+        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(k2) {
+            return { keyAttributes: { k: k2, v: this.tags[k2] } };
+          }, this)
         }
+      };
+      if (changeset_id) {
+        r2.way["@changeset"] = changeset_id;
       }
-      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;
-              }
-            }
-          }
-        } else {
-          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
+      return r2;
+    },
+    asGeoJSON: function(resolver) {
+      return resolver.transient(this, "GeoJSON", function() {
+        var coordinates = resolver.childNodes(this).map(function(n3) {
+          return n3.loc;
+        });
+        if (this.isArea() && this.isClosed()) {
+          return {
+            type: "Polygon",
+            coordinates: [coordinates]
           };
-          var insertPair = {
-            originalID: wayA.id,
-            insertedID: wayB.id,
-            nodes: origNodes
+        } else {
+          return {
+            type: "LineString",
+            coordinates
           };
-          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: {} }));
+    },
+    area: function(resolver) {
+      return resolver.transient(this, "area", function() {
+        var nodes = resolver.childNodes(this);
+        var json = {
+          type: "Polygon",
+          coordinates: [nodes.map(function(n3) {
+            return n3.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, i3, arr) {
+    return i3 === 0 || node !== arr[i3 - 1];
+  }
+
+  // modules/osm/multipolygon.js
+  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 i3;
+    var joinAsMembers = true;
+    for (i3 = 0; i3 < toJoin.length; i3++) {
+      if (toJoin[i3] instanceof osmWay) {
+        joinAsMembers = false;
+        break;
       }
-      _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;
+    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 (i3 = 0; i3 < toJoin.length; i3++) {
+          item = toJoin[i3];
+          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;
+          }
+        }
+        if (!nodes) {
+          break;
+        }
+        fn.apply(currWays, [item]);
+        fn.apply(currNodes, nodes);
+        toJoin.splice(i3, 1);
+      }
+      currWays.nodes = currNodes;
+      sequences.push(currWays);
+    }
+    return sequences;
+  }
+
+  // modules/actions/add_member.js
+  function actionAddMember(relationId, member, memberIndex) {
+    return function action(graph) {
+      var relation = graph.entity(relationId);
+      var isPTv2 = /stop|platform/.test(member.role);
+      if (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.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";
-        });
-        if (hasLine) {
-          return splittableParents.filter(function(parent) {
-            return parent.geometry(graph) === "line";
-          });
+    function addWayMember(relation, graph) {
+      var groups, item, i3, j2, k2;
+      var PTv2members = [];
+      var members = [];
+      for (i3 = 0; i3 < relation.members.length; i3++) {
+        var m2 = relation.members[i3];
+        if (/stop|platform/.test(m2.role)) {
+          PTv2members.push(m2);
+        } else {
+          members.push(m2);
         }
       }
-      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;
+      relation = relation.update({ members });
+      groups = utilArrayGroupBy(relation.members, "type");
+      groups.way = groups.way || [];
+      groups.way.push(member);
+      members = withIndex(groups.way);
+      var joined = osmJoinWays(members, graph);
+      for (i3 = 0; i3 < joined.length; i3++) {
+        var segment = joined[i3];
+        var nodes = segment.nodes.slice();
+        var startIndex = segment[0].index;
+        for (j2 = 0; j2 < members.length; j2++) {
+          if (members[j2].index === startIndex) {
+            break;
+          }
+        }
+        for (k2 = 0; k2 < segment.length; k2++) {
+          item = segment[k2];
+          var way = graph.entity(item.id);
+          if (k2 > 0) {
+            if (j2 + k2 >= members.length || item.index !== members[j2 + k2].index) {
+              moveMember(members, item.index, j2 + k2);
+            }
+          }
+          nodes.splice(0, way.nodes.length - 1);
         }
-        return false;
       }
-    };
-    action.ways = function(graph) {
-      return utilArrayUniq([].concat.apply([], nodeIds.map(function(nodeId) {
-        return action.waysForNode(nodeId, 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) {
-          return "not_eligible";
+      var wayMembers = [];
+      for (i3 = 0; i3 < members.length; i3++) {
+        item = members[i3];
+        if (item.index === -1) continue;
+        wayMembers.push(utilObjectOmit(item, ["index"]));
+      }
+      var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
+      return graph.replace(relation.update({ members: newMembers }));
+      function moveMember(arr, findIndex, toIndex) {
+        var i4;
+        for (i4 = 0; i4 < arr.length; i4++) {
+          if (arr[i4].index === findIndex) {
+            break;
+          }
         }
+        var item2 = Object.assign({}, arr[i4]);
+        arr[i4].index = -1;
+        delete item2.index;
+        arr.splice(toIndex, 0, item2);
       }
+      function withIndex(arr) {
+        var result = new Array(arr.length);
+        for (var i4 = 0; i4 < arr.length; i4++) {
+          result[i4] = Object.assign({}, arr[i4]);
+          result[i4].index = i4;
+        }
+        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 i3 = 0; i3 < way.nodes.length - 1; i3++) {
+          if (geoEdgeEqual([way.nodes[i3], way.nodes[i3 + 1]], midpoint.edge)) {
+            graph = graph.replace(graph.entity(way.id).addNode(node.id, i3 + 1));
+            return;
+          }
+        }
+      });
+      return graph;
     };
-    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;
+  }
+
+  // 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/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]);
-    }
-    this.transients = {};
-    this._childNodes = {};
-    this.frozen = !mutable;
+  // modules/actions/change_member.js
+  function actionChangeMember(relationId, member, memberIndex) {
+    return function(graph) {
+      return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
+    };
   }
-  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;
-    },
-    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];
-      }
-      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);
+
+  // 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 (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));
+        }
       }
-      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);
-      }
-      return result;
+      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/change_tags.js
+  function actionChangeTags(entityId, tags) {
+    return function(graph) {
+      var entity = graph.entity(entityId);
+      return graph.replace(entity.update({ tags }));
+    };
+  }
+
+  // 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);
     },
-    parentMultipolygons: function(entity) {
-      return this.parentRelations(entity).filter(function(relation) {
-        return relation.isMultipolygon();
+    geometry: function(graph) {
+      return graph.transient(this, "geometry", function() {
+        return graph.isPoi(this) ? "point" : "vertex";
       });
     },
-    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]);
-      }
-      if (debug)
-        Object.freeze(nodes);
-      this._childNodes[entity.id] = nodes;
-      return this._childNodes[entity.id];
+    move: function(loc) {
+      return this.update({ loc });
     },
-    base: function() {
-      return {
-        "entities": Object.getPrototypeOf(this.entities),
-        "parentWays": Object.getPrototypeOf(this._parentWays),
-        "parentRels": Object.getPrototypeOf(this._parentRels)
-      };
+    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);
     },
-    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];
-              }
-            }
+    // Inspect tags and geometry to determine which direction(s) this node/vertex points
+    directions: function(resolver, projection2) {
+      var val;
+      var i3;
+      if (this.isHighwayIntersection(resolver) && (this.tags.stop || "").toLowerCase() === "all") {
+        val = "all";
+      } else {
+        val = (this.tags.direction || "").toLowerCase();
+        var re3 = /:direction$/i;
+        var keys2 = Object.keys(this.tags);
+        for (i3 = 0; i3 < keys2.length; i3++) {
+          if (re3.test(keys2[i3])) {
+            val = this.tags[keys2[i3]].toLowerCase();
+            break;
           }
         }
       }
-      for (i2 = 0; i2 < stack.length; i2++) {
-        stack[i2]._updateRebased();
-      }
-    },
-    _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);
+      if (val === "") return [];
+      var values = val.split(";");
+      var results = [];
+      values.forEach(function(v2) {
+        if (cardinal[v2] !== void 0) {
+          v2 = cardinal[v2];
         }
-      }, 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);
+        if (v2 !== "" && !isNaN(+v2)) {
+          results.push(+v2);
+          return;
         }
+        var lookBackward = this.tags["traffic_sign:backward"] || v2 === "backward" || v2 === "both" || v2 === "all";
+        var lookForward = this.tags["traffic_sign:forward"] || v2 === "forward" || v2 === "both" || v2 === "all";
+        if (!lookForward && !lookBackward) return;
+        var nodeIds = {};
+        resolver.parentWays(this).forEach(function(parent) {
+          var nodes = parent.nodes;
+          for (i3 = 0; i3 < nodes.length; i3++) {
+            if (nodes[i3] === this.id) {
+              if (lookForward && i3 > 0) {
+                nodeIds[nodes[i3 - 1]] = true;
+              }
+              if (lookBackward && i3 < nodes.length - 1) {
+                nodeIds[nodes[i3 + 1]] = true;
+              }
+            }
+          }
+        }, this);
+        Object.keys(nodeIds).forEach(function(nodeId) {
+          results.push(
+            geoAngle(this, resolver.entity(nodeId), projection2) * (180 / Math.PI) + 90
+          );
+        }, this);
       }, this);
-      this.transients = {};
+      return utilArrayUniq(results);
     },
-    _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;
-        }
-        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);
+    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;
+      });
+    },
+    isConnected: function(resolver) {
+      return resolver.transient(this, "isConnected", function() {
+        var parents = resolver.parentWays(this);
+        if (parents.length > 1) {
+          for (var i3 in parents) {
+            if (parents[i3].geometry(resolver) === "line" && parents[i3].hasInterestingTags()) return true;
+          }
+        } 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);
         }
-      }
+        return false;
+      });
     },
-    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;
+    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";
+        });
       });
     },
-    remove: function(entity) {
-      return this.update(function() {
-        this._updateCalculated(entity, void 0);
-        this.entities[entity.id] = void 0;
+    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;
       });
     },
-    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];
+    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;
       });
     },
-    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;
+    asJXON: function(changeset_id) {
+      var r2 = {
+        node: {
+          "@id": this.osmId(),
+          "@lon": this.loc[0],
+          "@lat": this.loc[1],
+          "@version": this.version || 0,
+          tag: Object.keys(this.tags).map(function(k2) {
+            return { keyAttributes: { k: k2, v: this.tags[k2] } };
+          }, this)
+        }
+      };
+      if (changeset_id) r2.node["@changeset"] = changeset_id;
+      return r2;
     },
-    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]);
-      }
-      return this;
+    asGeoJSON: function() {
+      return {
+        type: "Point",
+        coordinates: this.loc
+      };
     }
-  };
+  });
 
-  // 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();
+  // modules/actions/circularize.js
+  function actionCircularize(wayId, projection2, maxAngle) {
+    maxAngle = (maxAngle || 20) * Math.PI / 180;
+    var action = function(graph, t2) {
+      if (t2 === null || !isFinite(t2)) t2 = 1;
+      t2 = Math.min(Math.max(+t2, 0), 1);
+      var way = graph.entity(wayId);
+      var origNodes = {};
+      graph.childNodes(way).forEach(function(node2) {
+        if (!origNodes[node2.id]) origNodes[node2.id] = node2;
       });
-    }
-    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;
-          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;
-          }
-          if (hasParents) {
-            checkVertices.push(node);
-          }
-        }
-      }
-      if (hasWays) {
-        vertices.push(vertex);
+      if (!way.isConvex(graph)) {
+        graph = action.makeConvex(graph);
       }
-    }
-    vertices = utilArrayUniq(vertices);
-    ways = utilArrayUniq(ways);
-    ways.forEach(function(way2) {
-      graph.childNodes(way2).forEach(function(node2) {
-        vgraph = vgraph.replace(node2);
+      var nodes = utilArrayUniq(graph.childNodes(way));
+      var keyNodes = nodes.filter(function(n3) {
+        return graph.parentWays(n3).length !== 1;
       });
-      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));
-          }
-        }
+      var points = nodes.map(function(n3) {
+        return projection2(n3.loc);
       });
-    });
-    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 keyPoints = keyNodes.map(function(n3) {
+        return projection2(n3.loc);
+      });
+      var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : centroid_default2(points);
+      var radius = median(points, function(p2) {
+        return geoVecLength(centroid, p2);
+      });
+      var sign2 = area_default3(points) > 0 ? 1 : -1;
+      var ids, i3, j2, k2;
+      if (!keyNodes.length) {
+        keyNodes = [nodes[0]];
+        keyPoints = [points[0]];
       }
-    });
-    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);
-        });
+      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]);
       }
-    });
-    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;
+      for (i3 = 0; i3 < keyPoints.length; i3++) {
+        var nextKeyNodeIndex = (i3 + 1) % keyNodes.length;
+        var startNode = keyNodes[i3];
+        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;
         }
-        parents = vgraph.parentWays(vertex);
-        if (parents.length < 3) {
-          if (vertexIds.indexOf(vertexId) !== -1) {
-            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
-          }
+        var distance = geoVecLength(centroid, keyPoints[i3]) || 1e-4;
+        keyPoints[i3] = [
+          centroid[0] + (keyPoints[i3][0] - centroid[0]) / distance * radius,
+          centroid[1] + (keyPoints[i3][1] - centroid[1]) / distance * radius
+        ];
+        loc = projection2.invert(keyPoints[i3]);
+        node = keyNodes[i3];
+        origNode = origNodes[node.id];
+        node = node.move(geoVecInterp(origNode.loc, loc, t2));
+        graph = graph.replace(node);
+        startAngle = Math.atan2(keyPoints[i3][1] - centroid[1], keyPoints[i3][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));
         }
-        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;
-          }
+        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, t2));
+          graph = graph.replace(node);
         }
-        parents = vgraph.parentWays(vertex);
-        if (parents.length < 2) {
-          if (vertexIds.indexOf(vertexId) !== -1) {
-            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
+        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];
+            }
           }
-          removeVertexIds.push(vertexId);
-          keepGoing = true;
-        }
-        if (parents.length < 1) {
-          vgraph = vgraph.remove(vertex);
+          node = osmNode({ loc: geoVecInterp(origNode.loc, loc, t2) });
+          graph = graph.replace(node);
+          nodes.splice(endNodeIndex + j2, 0, node);
+          inBetweenNodes.push(node.id);
         }
-      }
-    } 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;
-                    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 });
+        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;
           }
-          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;
-                }
+          var parentWays = graph.parentWays(keyNodes[i3]);
+          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;
               }
-            }
-            var turn = pathToTurn(turnPath);
-            if (turn) {
-              if (matchedRestriction) {
-                turn.restrictionID = matchedRestriction.id;
-                turn.no = matchedRestriction.no;
-                turn.only = matchedRestriction.only;
-                turn.direct = matchedRestriction.direct;
+              if (wayDirection1 !== wayDirection2) {
+                inBetweenNodes.reverse();
+                insertAt = startIndex2;
               }
-              turns.push(osmTurn(turn));
+              for (k2 = 0; k2 < inBetweenNodes.length; k2++) {
+                sharedWay = sharedWay.addNode(inBetweenNodes[k2], insertAt + k2);
+              }
+              graph = graph.replace(sharedWay);
             }
-            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);
-          }
+      ids = nodes.map(function(n3) {
+        return n3.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(n3) {
+        return projection2(n3.loc);
+      });
+      var sign2 = area_default3(points) > 0 ? 1 : -1;
+      var hull = hull_default(points);
+      var i3, j2;
+      if (sign2 === -1) {
+        nodes.reverse();
+        points.reverse();
+      }
+      for (i3 = 0; i3 < hull.length - 1; i3++) {
+        var startIndex = points.indexOf(hull[i3]);
+        var endIndex = points.indexOf(hull[i3 + 1]);
+        var indexRange = endIndex - startIndex;
+        if (indexRange < 0) {
+          indexRange += nodes.length;
         }
-        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];
+        for (j2 = 1; j2 < indexRange; j2++) {
+          var point = geoVecInterp(hull[i3], hull[i3 + 1], j2 / indexRange);
+          var node = nodes[(j2 + startIndex) % nodes.length].move(projection2.invert(point));
+          graph = graph.replace(node);
+        }
+      }
+      return graph;
+    };
+    action.disabled = function(graph) {
+      if (!graph.entity(wayId).isClosed()) {
+        return "not_closed";
+      }
+      var way = graph.entity(wayId);
+      var nodes = utilArrayUniq(graph.childNodes(way));
+      var points = nodes.map(function(n3) {
+        return projection2(n3.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 i3, actualPoint;
+      for (i3 = 0; i3 < hull.length; i3++) {
+        actualPoint = hull[i3];
+        var actualDist = geoVecLengthSquare(actualPoint, centroid);
+        var diff = Math.abs(actualDist - radius);
+        if (diff > 0.05 * radius) {
+          return false;
+        }
+      }
+      for (i3 = 0; i3 < hull.length; i3++) {
+        actualPoint = hull[i3];
+        var nextPoint = hull[(i3 + 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";
     };
-    return intersection;
+    action.transitionable = true;
+    return action;
   }
-  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";
+
+  // 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();
     }
-    return "no_straight_on";
+    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);
+        }
+      });
+      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);
+    };
+    return action;
   }
 
-  // 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";
+  // 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 Object.assign(
-        { closedWay: [], multipolygon: [], other: [] },
-        geometryGroups
-      );
+      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 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 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);
+        }
       });
-      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;
-        });
-      }
-      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;
-      }
-      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);
+      var memberIDs = utilArrayUniq(relation.members.map(function(m2) {
+        return m2.id;
+      }));
+      memberIDs.forEach(function(memberID) {
+        graph = graph.replace(relation.removeMembersWithID(memberID));
+        var entity = graph.entity(memberID);
+        if (canDeleteEntity(entity, graph)) {
+          graph = actionDeleteMultiple([memberID])(graph);
         }
       });
-      entities.closedWay.forEach(function(way) {
-        function isThisOuter(m) {
-          return m.id === way.id && m.role !== "inner";
+      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);
         }
-        if (members.some(isThisOuter)) {
-          relation = relation.mergeTags(way.tags);
-          graph = graph.replace(way.update({ tags: {} }));
+      });
+      graph.parentRelations(node).forEach(function(parent) {
+        parent = parent.removeMembersWithID(nodeId);
+        graph = graph.replace(parent);
+        if (parent.isDegenerate()) {
+          graph = actionDeleteRelation(parent.id)(graph);
         }
       });
-      return graph.replace(relation.update({
-        members,
-        tags: utilObjectOmit(relation.tags, ["area"])
-      }));
+      return graph.remove(node);
     };
-    action.disabled = function(graph) {
-      var entities = groupEntities(graph);
-      if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
-        return "not_eligible";
+    return action;
+  }
+
+  // modules/actions/connect.js
+  function actionConnect(nodeIDs) {
+    var action = function(graph) {
+      var survivor;
+      var node;
+      var parents;
+      var i3, j2;
+      nodeIDs.reverse();
+      var interestingIDs = [];
+      for (i3 = 0; i3 < nodeIDs.length; i3++) {
+        node = graph.entity(nodeIDs[i3]);
+        if (node.hasInterestingTags()) {
+          if (!node.isNew()) {
+            interestingIDs.push(node.id);
+          }
+        }
       }
-      if (!entities.multipolygon.every(function(r) {
-        return r.isComplete(graph);
-      })) {
-        return "incomplete_relation";
+      survivor = graph.entity(utilOldestID(interestingIDs.length > 0 ? interestingIDs : nodeIDs));
+      for (i3 = 0; i3 < nodeIDs.length; i3++) {
+        node = graph.entity(nodeIDs[i3]);
+        if (node.id === survivor.id) continue;
+        parents = graph.parentWays(node);
+        for (j2 = 0; j2 < parents.length; j2++) {
+          graph = graph.replace(parents[j2].replaceNode(node.id, survivor.id));
+        }
+        parents = graph.parentRelations(node);
+        for (j2 = 0; j2 < parents.length; j2++) {
+          graph = graph.replace(parents[j2].replaceMember(node, survivor));
+        }
+        survivor = survivor.mergeTags(node.tags);
+        graph = actionDeleteNode(node.id)(graph);
       }
-      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";
+      graph = graph.replace(survivor);
+      parents = graph.parentWays(survivor);
+      for (i3 = 0; i3 < parents.length; i3++) {
+        if (parents[i3].isDegenerate()) {
+          graph = actionDeleteWay(parents[i3].id)(graph);
         }
-      } else if (entities.closedWay.some(function(way) {
-        return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
-      })) {
-        return "not_eligible";
       }
+      return graph;
     };
-    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;
+    action.disabled = function(graph) {
+      var seen = {};
+      var restrictionIDs = [];
+      var survivor;
+      var node, way;
+      var relations, relation, role;
+      var i3, j2, k2;
+      survivor = graph.entity(utilOldestID(nodeIDs));
+      for (i3 = 0; i3 < nodeIDs.length; i3++) {
+        node = graph.entity(nodeIDs[i3]);
+        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 (s < candidates.length) {
-          const newCandidate = { buffer1index: i2, buffer2index: j2, chain: candidates[s] };
-          if (r === candidates.length) {
-            candidates.push(c);
+          if (seen[relation.id] !== void 0 && seen[relation.id] !== role) {
+            return "relation";
           } else {
-            candidates[r] = c;
-          }
-          r = s + 1;
-          c = newCandidate;
-          if (r === candidates.length) {
-            break;
+            seen[relation.id] = role;
           }
         }
       }
-      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)
-        });
+      for (i3 = 0; i3 < nodeIDs.length; i3++) {
+        node = graph.entity(nodeIDs[i3]);
+        var parents = graph.parentWays(node);
+        for (j2 = 0; j2 < parents.length; j2++) {
+          var parent = parents[j2];
+          relations = graph.parentRelations(parent);
+          for (k2 = 0; k2 < relations.length; k2++) {
+            relation = relations[k2];
+            if (relation.hasFromViaTo()) {
+              restrictionIDs.push(relation.id);
+            }
+          }
+        }
       }
-    }
-    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)
+      restrictionIDs = utilArrayUniq(restrictionIDs);
+      for (i3 = 0; i3 < restrictionIDs.length; i3++) {
+        relation = graph.entity(restrictionIDs[i3]);
+        if (!relation.isComplete(graph)) continue;
+        var memberWays = relation.members.filter(function(m2) {
+          return m2.type === "way";
+        }).map(function(m2) {
+          return graph.entity(m2.id);
         });
-        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)
-          });
+        memberWays = utilArrayUniq(memberWays);
+        var f2 = relation.memberByRole("from");
+        var t2 = relation.memberByRole("to");
+        var isUturn = f2.id === t2.id;
+        var nodes = { from: [], via: [], to: [], keyfrom: [], keyto: [] };
+        for (j2 = 0; j2 < relation.members.length; j2++) {
+          collectNodes(relation.members[j2], nodes);
         }
-      } 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]);
+        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 n3 = nodeIDs[j2];
+          if (nodes.from.indexOf(n3) !== -1) {
+            connectFrom = true;
+          }
+          if (nodes.via.indexOf(n3) !== -1) {
+            connectVia = true;
+          }
+          if (nodes.to.indexOf(n3) !== -1) {
+            connectTo = true;
+          }
+          if (nodes.keyfrom.indexOf(n3) !== -1) {
+            connectKeyFrom = true;
+          }
+          if (nodes.keyto.indexOf(n3) !== -1) {
+            connectKeyTo = true;
+          }
         }
-        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;
-    }
-    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
-            }
-          });
+        if (connectFrom && connectTo && !isUturn) {
+          return "restriction";
         }
-      }
-    });
-    flushOk();
-    return results;
-  }
-
-  // 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;
-      }
-      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 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 (connectFrom && connectVia) {
+          return "restriction";
         }
-      }
-      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;
-      }
-      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;
+        if (connectTo && connectVia) {
+          return "restriction";
         }
-        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 });
+        if (connectKeyFrom || connectKeyTo) {
+          if (nodeIDs.length !== 2) {
+            return "restriction";
           }
-          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) } }));
+          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";
+            }
           }
-          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 });
-      }
-      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];
+        for (j2 = 0; j2 < memberWays.length; j2++) {
+          way = memberWays[j2].update({});
+          for (k2 = 0; k2 < nodeIDs.length; k2++) {
+            if (nodeIDs[k2] === survivor.id) continue;
+            if (way.areAdjacent(nodeIDs[k2], survivor.id)) {
+              way = way.removeNode(nodeIDs[k2]);
             } else {
-              delete tags[k];
+              way = way.replaceNode(nodeIDs[k2], survivor.id);
             }
-            changed = true;
+          }
+          if (way.isDegenerate()) {
+            return "restriction";
           }
         }
       }
-      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 false;
+      function hasDuplicates(n4, i4, arr) {
+        return arr.indexOf(n4) !== arr.lastIndexOf(n4);
+      }
+      function keyNodeFilter(froms, tos) {
+        return function(n4) {
+          return froms.indexOf(n4) === -1 && tos.indexOf(n4) === -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 graph.replace(target);
-        } else {
-          _conflicts.push(_t.html("merge_remote_changes.conflict.deleted", { user: { html: user(remote.user) } }));
-          return graph;
         }
       }
-      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 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);
+      });
+      for (var id2 in _copies) {
+        graph = graph.replace(_copies[id2]);
       }
       return graph;
     };
-    action.withOption = function(opt) {
-      _option = opt;
-      return action;
-    };
-    action.conflicts = function() {
-      return _conflicts;
+    action.copies = function() {
+      return _copies;
     };
     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;
+  // 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);
       }
-      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);
+      return graph;
+    };
+  }
+
+  // modules/actions/discard_tags.js
+  function actionDiscardTags(difference2, discardTags) {
+    discardTags = discardTags || {};
+    return (graph) => {
+      difference2.modified().forEach(checkTags);
+      difference2.created().forEach(checkTags);
+      return graph;
+      function checkTags(entity) {
+        const keys2 = Object.keys(entity.tags);
+        let didDiscard = false;
+        let tags = {};
+        for (let i3 = 0; i3 < keys2.length; i3++) {
+          const k2 = keys2[i3];
+          if (discardTags[k2] || !entity.tags[k2]) {
+            didDiscard = true;
           } else {
-            cacheEntities(entity.members.map(function(member) {
-              return member.id;
-            }));
+            tags[k2] = entity.tags[k2];
           }
         }
+        if (didDiscard) {
+          graph = graph.replace(entity.update({ tags }));
+        }
       }
-      function cacheIntersections(ids) {
-        function isEndpoint(way2, id3) {
-          return !way2.isClosed() && !!way2.affix(id3);
+    };
+  }
+
+  // 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));
         }
-        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;
+      });
+      return graph;
+    };
+    action.connections = function(graph) {
+      var candidates = [];
+      var keeping = false;
+      var parentWays = graph.parentWays(graph.entity(nodeId));
+      var way, waynode;
+      for (var i3 = 0; i3 < parentWays.length; i3++) {
+        way = parentWays[i3];
+        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 });
             }
-            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 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;
+          }
+        });
+      });
+      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 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);
-    }
-    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();
+    function extractFromWayOrRelation(entity, graph) {
+      var fromGeometry = entity.geometry(graph);
+      var keysToCopyAndRetain = ["source", "wheelchair"];
+      var keysToRetain = ["area"];
+      var buildingKeysToRetain = ["architect", "building", "height", "layer", "nycdoitt:bin"];
+      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();
       }
-      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);
-          }
+      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;
         }
-        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;
+        if (keysToRetain.indexOf(key) !== -1) {
+          continue;
         }
-      } 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);
-      }
-      for (var i2 = 0; i2 < cache.intersections.length; i2++) {
-        var obj = cache.intersections[i2];
-        if (obj.movedIsEP && obj.unmovedIsEP)
+        if (isBuilding) {
+          if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
+        }
+        if (isIndoorArea && key === "indoor") {
           continue;
-        if (!obj.movedIsEP)
+        }
+        pointTags[key] = entityTags[key];
+        if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
+          continue;
+        } else if (isIndoorArea && key === "level") {
           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);
         }
+        delete entityTags[key];
       }
-    }
-    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);
+      if (!isBuilding && !isIndoorArea && fromGeometry === "area") {
+        entityTags.area = "yes";
       }
-      return graph;
-    };
-    action.delta = function() {
-      return _delta;
+      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/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))
+  // 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);
+        })
       );
-    };
-    action.transitionable = true;
-    return action;
-  }
-
-  // modules/actions/noop.js
-  function actionNoop() {
-    return function(graph) {
+    }
+    var action = function(graph) {
+      var ways = ids.map(graph.entity, graph);
+      var survivorID = utilOldestID(ways.map((way) => way.id));
+      ways.sort(function(a2, b2) {
+        var aSided = a2.isSided();
+        var bSided = b2.isSided();
+        return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
+      });
+      var sequences = osmJoinWays(ways, graph);
+      var joined = sequences[0];
+      graph = sequences.actions.reduce(function(g3, action2) {
+        return action2(g3);
+      }, graph);
+      var survivor = graph.entity(survivorID);
+      survivor = survivor.update({ nodes: joined.nodes.map(function(n3) {
+        return n3.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;
+        }
+        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);
+      }
+      checkForSimpleMultipolygon();
       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;
+    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 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) });
+      var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
+      if (joined.length > 1) {
+        return "not_adjacent";
       }
-      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;
-          }
+      var i3;
+      var sortedParentRelations = function(id2) {
+        return graph.parentRelations(graph.entity(id2)).filter((rel) => !rel.isRestriction() && !rel.isConnectivity()).sort((a2, b2) => a2.id - b2.id);
+      };
+      var relsA = sortedParentRelations(ids[0]);
+      for (i3 = 1; i3 < ids.length; i3++) {
+        var relsB = sortedParentRelations(ids[i3]);
+        if (!utilArrayIdentical(relsA, relsB)) {
+          return "conflicting_relations";
         }
-        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);
+      }
+      for (i3 = 0; i3 < ids.length - 1; i3++) {
+        for (var j2 = i3 + 1; j2 < ids.length; j2++) {
+          var path1 = graph.childNodes(graph.entity(ids[i3])).map(function(e3) {
+            return e3.loc;
+          });
+          var path2 = graph.childNodes(graph.entity(ids[j2])).map(function(e3) {
+            return e3.loc;
+          });
+          var intersections = geoPathIntersections(path1, path2);
+          var common = utilArrayIntersection(
+            joined[0].nodes.map(function(n3) {
+              return n3.loc.toString();
+            }),
+            intersections.map(function(n3) {
+              return n3.toString();
+            })
+          );
+          if (common.length !== intersections.length) {
+            return "paths_intersect";
           }
         }
-        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;
+      }
+      var nodeIds = joined[0].nodes.map(function(n3) {
+        return n3.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(m2) {
+            return nodeIds.indexOf(m2.id) >= 0;
+          })) {
+            relation = parent;
           }
-          if (score < epsilon3) {
-            break;
+        });
+        for (var k2 in way.tags) {
+          if (!(k2 in tags)) {
+            tags[k2] = way.tags[k2];
+          } else if (tags[k2] && osmIsInterestingTag(k2) && tags[k2] !== way.tags[k2]) {
+            conflicting = true;
           }
         }
-        var bestCoords = bestPoints.map(function(p) {
-          return p.coord;
+      });
+      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));
         });
-        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)));
+        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 i3;
+          var node;
+          for (i3 = 0; i3 < nodes.length; i3++) {
+            node = nodes[i3];
+            if (canBeReplaced(node) && node.isNew()) {
+              replaceNode(node);
+              break;
+            }
           }
-        }
-        for (i2 = 0; i2 < straights.length; i2++) {
-          point = straights[i2];
-          if (nodeCount[point.id] > 1)
-            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 (!inserted && point.hasInterestingTags()) {
+            for (i3 = 0; i3 < nodes.length; i3++) {
+              node = nodes[i3];
+              if (canBeReplaced(node) && !node.hasInterestingTags()) {
+                replaceNode(node);
+                break;
+              }
+            }
+            if (!inserted) {
+              for (i3 = 0; i3 < nodes.length; i3++) {
+                node = nodes[i3];
+                if (canBeReplaced(node) && utilCompareIDs(point.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;
-      function clonePoints(array2) {
-        return array2.map(function(p) {
-          return { id: p.id, coord: [p.coord[0], p.coord[1]] };
-        });
-      }
-      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);
-        }
-        return [0, 0];
+    };
+    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";
       }
     };
-    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 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 i3 = 0; i3 < nodeIDs.length; i3++) {
+        var node = graph.entity(nodeIDs[i3]);
+        if (node.hasInterestingTags()) {
+          interestingLoc = ++interestingCount === 1 ? node.loc : null;
         }
+        sum = geoVecAdd(sum, node.loc);
       }
-      return [];
+      return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
     }
-    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 action = function(graph) {
+      if (nodeIDs.length < 2) return graph;
+      var toLoc = loc;
+      if (!toLoc) {
+        toLoc = chooseLoc(graph);
       }
-      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;
+      for (var i3 = 0; i3 < nodeIDs.length; i3++) {
+        var node = graph.entity(nodeIDs[i3]);
+        if (node.loc !== toLoc) {
+          graph = graph.replace(node.move(toLoc));
+        }
       }
+      return actionConnect(nodeIDs)(graph);
     };
-    action.transitionable = true;
-    return action;
-  }
-
-  // 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" });
-        });
+    action.disabled = function(graph) {
+      if (nodeIDs.length < 2) return "not_eligible";
+      for (var i3 = 0; i3 < nodeIDs.length; i3++) {
+        var entity = graph.entity(nodeIDs[i3]);
+        if (entity.type !== "node") return "not_eligible";
       }
-      members.push({ id: toWay.id, type: "way", role: "to" });
-      return graph.replace(osmRelation({
-        id: restrictionID,
-        tags: {
-          type: "restriction",
-          restriction: restrictionType
-        },
-        members
-      }));
+      return actionConnect(nodeIDs).disabled(graph);
     };
+    return action;
   }
 
-  // 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);
-            }
+  // modules/osm/changeset.js
+  function osmChangeset() {
+    if (!(this instanceof osmChangeset)) {
+      return new osmChangeset().initialize(arguments);
+    } else if (arguments.length) {
+      this.initialize(arguments);
+    }
+  }
+  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(k2) {
+              return { "@k": k2, "@v": this.tags[k2] };
+            }, this),
+            "@version": 0.6,
+            "@generator": "iD"
+          }
+        }
+      };
+    },
+    // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
+    // XML. Returns a string.
+    osmChangeJXON: function(changes) {
+      var changeset_id = this.id;
+      function nest(x2, order) {
+        var groups = {};
+        for (var i3 = 0; i3 < x2.length; i3++) {
+          var tagName = Object.keys(x2[i3])[0];
+          if (!groups[tagName]) groups[tagName] = [];
+          groups[tagName].push(x2[i3][tagName]);
+        }
+        var ordered = {};
+        order.forEach(function(o2) {
+          if (groups[o2]) ordered[o2] = groups[o2];
+        });
+        return ordered;
+      }
+      function sort(changes2) {
+        function resolve(item) {
+          return relations.find(function(relation2) {
+            return item.keyAttributes.type === "relation" && item.keyAttributes.ref === relation2["@id"];
           });
         }
-        graph.parentRelations(entity).forEach(function(parent) {
-          parent = parent.removeMembersWithID(id2);
-          graph = graph.replace(parent);
-          if (parent.isDegenerate()) {
-            graph = actionDeleteRelation(parent.id)(graph);
+        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 i3 = 0; i3 < relations.length; i3++) {
+          var relation = relations[i3];
+          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 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)));
-        });
-      });
-    };
-  }
+      function rep(entity) {
+        return entity.asJXON(changeset_id);
+      }
+      return {
+        osmChange: {
+          "@version": 0.6,
+          "@generator": "iD",
+          "create": sort(nest(changes.created.map(rep), ["node", "way", "relation"])),
+          "modify": nest(changes.modified.map(rep), ["node", "way", "relation"]),
+          "delete": Object.assign(nest(changes.deleted.map(rep), ["relation", "way", "node"]), { "@if-unused": true })
+        }
+      };
+    },
+    asGeoJSON: function() {
+      return {};
+    }
+  });
 
-  // modules/actions/straighten_nodes.js
-  function actionStraightenNodes(nodeIDs, projection2) {
-    function positionAlongWay(a, o, b) {
-      return geoVecDot(a, b, o) / geoVecDot(b, b, o);
+  // modules/osm/note.js
+  function osmNote() {
+    if (!(this instanceof osmNote)) {
+      return new osmNote().initialize(arguments);
+    } else if (arguments.length) {
+      this.initialize(arguments);
     }
-    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];
+  }
+  osmNote.id = function() {
+    return osmNote.id.next--;
+  };
+  osmNote.id.next = -1;
+  Object.assign(osmNote.prototype, {
+    type: "note",
+    initialize: function(sources) {
+      for (var i3 = 0; i3 < sources.length; ++i3) {
+        var source = sources[i3];
+        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];
+            }
+          }
+        }
       }
-      return [p2, q2];
+      if (!this.id) {
+        this.id = osmNote.id().toString();
+      }
+      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 });
     }
-    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);
+  });
+
+  // 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(a2, b2) {
+    var aId = parseInt(osmEntity.id.toOSM(a2.id), 10);
+    var bId = parseInt(osmEntity.id.toOSM(b2.id), 10);
+    if (aId < 0 || bId < 0) return aId - bId;
+    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 });
       });
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
+      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 i3 = 0; i3 < this.members.length; i3++) {
+          var member = resolver.hasEntity(this.members[i3].id);
+          if (member) {
+            extent._extend(member.extent(resolver, memo));
+          }
+        }
+        return extent;
       });
-      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)));
-      }
-      return graph;
-    };
-    action.disabled = function(graph) {
-      var nodes = nodeIDs.map(function(id2) {
-        return graph.entity(id2);
+    },
+    geometry: function(graph) {
+      return graph.transient(this, "geometry", function() {
+        return this.isMultipolygon() ? "area" : "relation";
       });
-      var points = nodes.map(function(n2) {
-        return projection2(n2.loc);
+    },
+    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 i3 = 0; i3 < this.members.length; i3++) {
+        result[i3] = Object.assign({}, this.members[i3], { index: i3 });
+      }
+      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 i3 = 0; i3 < this.members.length; i3++) {
+        if (this.members[i3].role === role) {
+          return Object.assign({}, this.members[i3], { index: i3 });
+        }
+      }
+    },
+    // Same as memberByRole, but returns all members with the given role
+    membersByRole: function(role) {
+      var result = [];
+      for (var i3 = 0; i3 < this.members.length; i3++) {
+        if (this.members[i3].role === role) {
+          result.push(Object.assign({}, this.members[i3], { index: i3 }));
+        }
+      }
+      return result;
+    },
+    // 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 i3 = 0; i3 < this.members.length; i3++) {
+        if (this.members[i3].id === id2) {
+          return Object.assign({}, this.members[i3], { index: i3 });
+        }
+      }
+    },
+    // 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 i3 = 0; i3 < this.members.length; i3++) {
+        if (this.members[i3].id === id2 && this.members[i3].role === role) {
+          return Object.assign({}, this.members[i3], { index: i3 });
+        }
+      }
+    },
+    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(m2) {
+        return m2.id !== id2;
       });
-      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;
+      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 });
+    },
+    // 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;
+      var members = [];
+      for (var i3 = 0; i3 < this.members.length; i3++) {
+        var member = this.members[i3];
+        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 });
         }
       }
-      if (maxDistance < 1e-4) {
-        return "straight_enough";
+      return this.update({ members });
+    },
+    asJXON: function(changeset_id) {
+      var r2 = {
+        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(k2) {
+            return { keyAttributes: { k: k2, v: this.tags[k2] } };
+          }, this)
+        }
+      };
+      if (changeset_id) {
+        r2.relation["@changeset"] = changeset_id;
       }
-    };
-    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";
+      return r2;
+    },
+    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));
+            })
+          };
+        }
       });
-      var selectedNodes = selectedIDs.filter(function(n2) {
-        return graph.entity(n2).type === "node";
+    },
+    area: function(resolver) {
+      return resolver.transient(this, "area", function() {
+        return area_default(this.asGeoJSON(resolver));
       });
-      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]);
+    },
+    isMultipolygon: function() {
+      return this.tags.type === "multipolygon";
+    },
+    isComplete: function(resolver) {
+      for (var i3 = 0; i3 < this.members.length; i3++) {
+        if (!resolver.hasEntity(this.members[i3].id)) {
+          return false;
+        }
       }
-      startNodes = startNodes.filter(function(n2) {
-        return startNodes.indexOf(n2) === startNodes.lastIndexOf(n2);
+      return true;
+    },
+    hasFromViaTo: function() {
+      return this.members.some(function(m2) {
+        return m2.role === "from";
+      }) && this.members.some(function(m2) {
+        return m2.role === "via";
+      }) && this.members.some(function(m2) {
+        return m2.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(m2) {
+        return m2.role === "from";
+      });
+      var vias = this.members.filter(function(m2) {
+        return m2.role === "via";
+      });
+      var tos = this.members.filter(function(m2) {
+        return m2.role === "to";
+      });
+      if (froms.length !== 1 && this.tags.restriction !== "no_entry") return false;
+      if (froms.some(function(m2) {
+        return m2.type !== "way";
+      })) return false;
+      if (tos.length !== 1 && this.tags.restriction !== "no_exit") return false;
+      if (tos.some(function(m2) {
+        return m2.type !== "way";
+      })) return false;
+      if (vias.length === 0) return false;
+      if (vias.length > 1 && vias.some(function(m2) {
+        return m2.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(m2) {
+        return "outer" === (m2.role || "outer");
       });
-      endNodes = endNodes.filter(function(n2) {
-        return endNodes.indexOf(n2) === endNodes.lastIndexOf(n2);
+      var inners = this.members.filter(function(m2) {
+        return "inner" === m2.role;
       });
-      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];
+      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;
+        });
       };
-      while (remainingWays.length) {
-        nextWay = getNextWay(currNode, remainingWays);
-        remainingWays = utilArrayDifference(remainingWays, [nextWay]);
-        if (nextWay[0] !== currNode) {
-          nextWay.reverse();
+      outers = outers.map(sequenceToLineString);
+      inners = inners.map(sequenceToLineString);
+      var result = outers.map(function(o3) {
+        return [area_default({ type: "Polygon", coordinates: [o3] }) > 2 * Math.PI ? o3.reverse() : o3];
+      });
+      function findOuter(inner2) {
+        var o3, outer;
+        for (o3 = 0; o3 < outers.length; o3++) {
+          outer = outers[o3];
+          if (geoPolygonContainsPolygon(outer, inner2)) {
+            return o3;
+          }
+        }
+        for (o3 = 0; o3 < outers.length; o3++) {
+          outer = outers[o3];
+          if (geoPolygonIntersectsPolygon(outer, inner2, false)) {
+            return o3;
+          }
         }
-        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);
+      for (var i3 = 0; i3 < inners.length; i3++) {
+        var inner = inners[i3];
+        if (area_default({ type: "Polygon", coordinates: [inner] }) < 2 * Math.PI) {
+          inner = inner.reverse();
+        }
+        var o2 = findOuter(inners[i3]);
+        if (o2 !== void 0) {
+          result[o2].push(inners[i3]);
+        } else {
+          result.push([inners[i3]]);
+        }
       }
-      return nodes.map(function(n2) {
-        return graph.entity(n2);
-      });
+      return result;
     }
-    function shouldKeepNode(node, graph) {
-      return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
+  });
+
+  // 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 : "".concat(_QAItem.id());
+      this.update(props);
+      if (service && typeof service.getIcon === "function") {
+        this.icon = service.getIcon(itemType);
+      }
     }
-    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);
-          }
-        }
+    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";
+    const circularJunctions = ["roundabout", "circular"];
+    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 length2;
+      var i3;
+      var best = 0;
+      var idxB;
+      function wrap2(index) {
+        return utilWrap(index, nodes.length);
       }
-      for (i2 = 0; i2 < toDelete.length; i2++) {
-        graph = actionDeleteNode(toDelete[i2].id)(graph);
+      length2 = 0;
+      for (i3 = wrap2(idxA + 1); i3 !== idxA; i3 = wrap2(i3 + 1)) {
+        length2 += dist(graph, nodes[i3], nodes[wrap2(i3 - 1)]);
+        lengths[i3] = length2;
       }
-      return graph;
-    };
-    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";
+      length2 = 0;
+      for (i3 = wrap2(idxA - 1); i3 !== idxA; i3 = wrap2(i3 - 1)) {
+        length2 += dist(graph, nodes[i3], nodes[wrap2(i3 + 1)]);
+        if (length2 < lengths[i3]) {
+          lengths[i3] = length2;
+        }
       }
-      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;
+      for (i3 = 0; i3 < nodes.length; i3++) {
+        var cost = lengths[i3] / dist(graph, nodes[idxA], nodes[i3]);
+        if (cost > best) {
+          idxB = i3;
+          best = cost;
         }
       }
-      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";
+      return idxB;
+    }
+    function totalLengthBetweenNodes(graph, nodes) {
+      var totalLength = 0;
+      for (var i3 = 0; i3 < nodes.length - 1; i3++) {
+        totalLength += dist(graph, nodes[i3], nodes[i3 + 1]);
       }
-    };
-    action.transitionable = true;
-    return action;
-  }
-
-  // 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;
+      return totalLength;
+    }
+    function split(graph, nodeId, wayA, newWayId) {
+      var wayB = osmWay({ id: newWayId, tags: wayA.tags });
+      var nodesA;
+      var nodesB;
+      var isArea = wayA.isArea();
+      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 {
-        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);
+        var idx = wayA.nodes.indexOf(nodeId, 1);
+        nodesA = wayA.nodes.slice(0, idx + 1);
+        nodesB = wayA.nodes.slice(idx);
       }
-      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(";");
-          }
+      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 });
         }
       }
-      if (replaceTags) {
-        for (var replaceKey in replaceTags) {
-          var replaceValue = replaceTags[replaceKey];
-          if (replaceValue === "*") {
-            if (tags[replaceKey] && tags[replaceKey] !== "no") {
-              continue;
+      graph = graph.replace(wayA);
+      graph = graph.replace(wayB);
+      graph.parentRelations(wayA).forEach(function(relation) {
+        if (relation.hasFromViaTo()) {
+          var f2 = relation.memberByRole("from");
+          var v2 = relation.membersByRole("via");
+          var t2 = relation.memberByRole("to");
+          var i3;
+          if (f2.id === wayA.id || t2.id === wayA.id) {
+            var keepB = false;
+            if (v2.length === 1 && v2[0].type === "node") {
+              keepB = wayB.contains(v2[0].id);
             } else {
-              tags[replaceKey] = "yes";
+              for (i3 = 0; i3 < v2.length; i3++) {
+                if (v2[i3].type === "way") {
+                  var wayVia = graph.hasEntity(v2[i3].id);
+                  if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
+                    keepB = true;
+                    break;
+                  }
+                }
+              }
+            }
+            if (keepB) {
+              relation = relation.replaceMember(wayA, wayB);
+              graph = graph.replace(relation);
             }
-          } 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(";");
+            for (i3 = 0; i3 < v2.length; i3++) {
+              if (v2[i3].type === "way" && v2[i3].id === wayA.id) {
+                graph = splitWayMember(graph, relation.id, wayA, wayB);
               }
-            } else {
-              tags[replaceKey] = replaceValue;
             }
           }
+        } else {
+          graph = splitWayMember(graph, relation.id, wayA, wayB);
         }
+      });
+      if (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: {} }));
       }
-      return graph.replace(entity.update({ tags }));
-    };
-  }
-
-  // modules/behavior/edit.js
-  function behaviorEdit(context) {
-    function behavior() {
-      context.map().minzoom(context.minEditableZoom());
-    }
-    behavior.off = function() {
-      context.map().minzoom(0);
-    };
-    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);
-      }
-    }
-    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);
-      }
+      _createdWayIDs.push(wayB.id);
+      return graph;
     }
-    function behavior(selection2) {
-      _selection = selection2;
-      _targets = [];
-      if (_initialNodeID) {
-        _newNodeId = _initialNodeID;
-        _initialNodeID = null;
-      } else {
-        _newNodeId = null;
+    function splitWayMember(graph, relationId, wayA, wayB) {
+      function connects(way1, way2) {
+        if (way1.nodes.length < 2 || way2.nodes.length < 2) return false;
+        if (circularJunctions.includes(way1.tags.junction) && way1.isClosed()) {
+          return way1.nodes.some((nodeId) => nodeId === way2.nodes[0] || nodeId === way2.nodes[way2.nodes.length - 1]);
+        } else if (circularJunctions.includes(way2.tags.junction) && way2.isClosed()) {
+          return way2.nodes.some((nodeId) => nodeId === way1.nodes[0] || nodeId === way1.nodes[way1.nodes.length - 1]);
+        }
+        if (way1.nodes[0] === way2.nodes[0]) return true;
+        if (way1.nodes[0] === way2.nodes[way2.nodes.length - 1]) return true;
+        if (way1.nodes[way1.nodes.length - 1] === way2.nodes[way2.nodes.length - 1]) return true;
+        if (way1.nodes[way1.nodes.length - 1] === way2.nodes[0]) return true;
+        return false;
       }
-      _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;
+      let relation = graph.entity(relationId);
+      const insertMembers = [];
+      const members = relation.members;
+      for (let i3 = 0; i3 < members.length; i3++) {
+        const member = members[i3];
+        if (member.id === wayA.id) {
+          let wayAconnectsPrev = false;
+          let wayAconnectsNext = false;
+          let wayBconnectsPrev = false;
+          let wayBconnectsNext = false;
+          if (i3 > 0 && graph.hasEntity(members[i3 - 1].id)) {
+            const prevEntity = graph.entity(members[i3 - 1].id);
+            if (prevEntity.type === "way") {
+              wayAconnectsPrev = connects(prevEntity, wayA);
+              wayBconnectsPrev = connects(prevEntity, wayB);
+            }
+          }
+          if (i3 < members.length - 1 && graph.hasEntity(members[i3 + 1].id)) {
+            const nextEntity = graph.entity(members[i3 + 1].id);
+            if (nextEntity.type === "way") {
+              wayAconnectsNext = connects(nextEntity, wayA);
+              wayBconnectsNext = connects(nextEntity, wayB);
+            }
+          }
+          if (wayAconnectsPrev && !wayAconnectsNext || !wayBconnectsPrev && wayBconnectsNext && !(!wayAconnectsPrev && wayAconnectsNext)) {
+            insertMembers.push({ at: i3 + 1, role: member.role });
+            continue;
+          }
+          if (!wayAconnectsPrev && wayAconnectsNext || wayBconnectsPrev && !wayBconnectsNext && !(wayAconnectsPrev && !wayAconnectsNext)) {
+            insertMembers.push({ at: i3, role: member.role });
+            continue;
+          }
+          if (wayAconnectsPrev && wayBconnectsPrev && wayAconnectsNext && wayBconnectsNext) {
+            if (i3 > 2 && graph.hasEntity(members[i3 - 2].id)) {
+              const prev2Entity = graph.entity(members[i3 - 2].id);
+              if (connects(prev2Entity, wayA) && !connects(prev2Entity, wayB)) {
+                insertMembers.push({ at: i3, role: member.role });
+                continue;
+              }
+              if (connects(prev2Entity, wayB) && !connects(prev2Entity, wayA)) {
+                insertMembers.push({ at: i3 + 1, role: member.role });
+                continue;
+              }
+            }
+            if (i3 < members.length - 2 && graph.hasEntity(members[i3 + 2].id)) {
+              const next2Entity = graph.entity(members[i3 + 2].id);
+              if (connects(next2Entity, wayA) && !connects(next2Entity, wayB)) {
+                insertMembers.push({ at: i3 + 1, role: member.role });
+                continue;
+              }
+              if (connects(next2Entity, wayB) && !connects(next2Entity, wayA)) {
+                insertMembers.push({ at: i3, role: member.role });
+                continue;
+              }
+            }
+          }
+          if (wayA.nodes[wayA.nodes.length - 1] === wayB.nodes[0]) {
+            insertMembers.push({ at: i3 + 1, role: member.role });
+          } else {
+            insertMembers.push({ at: i3, role: member.role });
+          }
         }
-        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);
+      insertMembers.reverse().forEach((item) => {
+        graph = graph.replace(relation.addMember({
+          id: wayB.id,
+          type: "way",
+          role: item.role
+        }, item.at));
+        relation = graph.entity(relation.id);
+      });
+      return graph;
+    }
+    var action = function(graph) {
+      _createdWayIDs = [];
+      var newWayIndex = 0;
+      for (var i3 = 0; i3 < nodeIds.length; i3++) {
+        var nodeId = nodeIds[i3];
+        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 pointerout(d3_event) {
-        var target = eventTarget(d3_event);
-        var index = _targets.indexOf(target);
-        if (index !== -1) {
-          _targets.splice(index);
-          updateHover(d3_event, _targets);
+      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";
+        });
+        if (hasLine) {
+          return splittableParents.filter(function(parent) {
+            return parent.geometry(graph) === "line";
+          });
         }
       }
-      function allowsVertex(d) {
-        return d.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d, context.graph());
-      }
-      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 splittableParents;
+      function isSplittable(parent) {
+        if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false;
+        if (parent.isClosed()) return true;
+        for (var i3 = 1; i3 < parent.nodes.length - 1; i3++) {
+          if (parent.nodes[i3] === nodeId) return true;
         }
-        return true;
+        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;
+    };
+    action.ways = function(graph) {
+      return utilArrayUniq([].concat.apply([], nodeIds.map(function(nodeId) {
+        return action.waysForNode(nodeId, graph);
+      })));
+    };
+    action.disabled = function(graph) {
+      for (const nodeId of nodeIds) {
+        const candidates = action.waysForNode(nodeId, graph);
+        if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
+          return "not_eligible";
         }
-        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;
+        for (const way of candidates) {
+          const parentRelations = graph.parentRelations(way);
+          for (const parentRelation of parentRelations) {
+            if (parentRelation.hasFromViaTo()) {
+              const vias = parentRelation.membersByRole("via");
+              if (!vias.every((via) => graph.hasEntity(via.id))) {
+                return "parent_incomplete";
+              }
+            } else {
+              for (let i3 = 0; i3 < parentRelation.members.length; i3++) {
+                if (parentRelation.members[i3].id === way.id) {
+                  const memberBeforePresent = i3 > 0 && graph.hasEntity(parentRelation.members[i3 - 1].id);
+                  const memberAfterPresent = i3 < parentRelation.members.length - 1 && graph.hasEntity(parentRelation.members[i3 + 1].id);
+                  if (!memberBeforePresent && !memberAfterPresent && parentRelation.members.length > 1) {
+                    return "parent_incomplete";
+                  }
+                }
               }
             }
+            const relTypesExceptions = ["junction", "enforcement"];
+            if (circularJunctions.includes(way.tags.junction) && way.isClosed() && !relTypesExceptions.includes(parentRelation.tags.type)) {
+              return "simple_roundabout";
+            }
           }
         }
-        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;
+    action.limitWays = function(val) {
+      if (!arguments.length) return _wayIDs;
+      _wayIDs = val;
+      return action;
     };
-    behavior.initialNodeID = function(nodeId) {
-      _initialNodeID = nodeId;
-      return behavior;
+    action.keepHistoryOn = function(val) {
+      if (!arguments.length) return _keepHistoryOn;
+      _keepHistoryOn = val;
+      return action;
     };
-    return utilRebind(behavior, dispatch10, "on");
+    return action;
   }
 
-  // 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/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]);
     }
-    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);
+    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];
       }
-    }
-    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);
-        }
+      if (!entity) {
+        throw new Error("entity " + id2 + " not found");
       }
-      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));
-    }
-    function pointercancel(d3_event) {
-      if (_downPointer && _downPointer.id === (d3_event.pointerId || "mouse")) {
-        if (!_downPointer.isCancelled) {
-          dispatch10.call("downcancel", this);
-        }
-        _downPointer = null;
+      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];
       }
-    }
-    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;
-      } 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;
-        }
-      } else if (mode.id !== "add-point" || mode.preset.matchGeometry("point")) {
-        var locLatLng = context.projection.invert(loc);
-        dispatch10.call("click", this, locLatLng, d);
+      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);
       }
-    }
-    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 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);
       }
-      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);
-    };
-    behavior.hover = function() {
-      return _hover;
-    };
-    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;
-    };
-  }
-
-  // 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();
-    }
-    while (++i2 < j2) {
-      d[i2] = normalize(domain2[i2], domain2[i2 + 1]);
-      r[i2] = interpolate(range3[i2], range3[i2 + 1]);
-    }
-    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 scale(x) {
-      return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain2.map(transform2), range3, interpolate)))(transform2(clamp3(x)));
-    }
-    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;
-    };
-    return function(t, u) {
-      transform2 = t, untransform = u;
-      return rescale();
-    };
-  }
-  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;
-  }
-
-  // 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);
-    };
-  }
-
-  // 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];
+      return result;
+    },
+    parentMultipolygons: function(entity) {
+      return this.parentRelations(entity).filter(function(relation) {
+        return relation.isMultipolygon();
       });
-    };
-  }
-
-  // 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;
-        }
+    },
+    childNodes: function(entity) {
+      if (this._childNodes[entity.id]) return this._childNodes[entity.id];
+      if (!entity.nodes) return [];
+      var nodes = [];
+      for (var i3 = 0; i3 < entity.nodes.length; i3++) {
+        nodes[i3] = this.entity(entity.nodes[i3]);
       }
-    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;
+      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 i3, j2, k2, id2;
+      for (i3 = 0; i3 < entities.length; i3++) {
+        var entity = entities[i3];
+        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 (k2 = 1; k2 < stack.length; k2++) {
+              var ents = stack[k2].entities;
+              if (ents.hasOwnProperty(id2) && ents[id2] === void 0) {
+                delete ents[id2];
               }
             }
           }
         }
-        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 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 {
-      format: newFormat,
-      formatPrefix: formatPrefix2
-    };
-  }
-
-  // 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;
+      for (i3 = 0; i3 < stack.length; i3++) {
+        stack[i3]._updateRebased();
       }
-      case "f":
-      case "%": {
-        if (specifier.precision == null && !isNaN(precision2 = precisionFixed_default(step)))
-          specifier.precision = precision2 - (specifier.type === "%") * 2;
-        break;
+    },
+    _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 = {};
+    },
+    // 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, i3;
+      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 (i3 = 0; i3 < removed.length; i3++) {
+          parentWays[removed[i3]] = new Set(parentWays[removed[i3]]);
+          parentWays[removed[i3]].delete(oldentity.id);
+        }
+        for (i3 = 0; i3 < added.length; i3++) {
+          parentWays[added[i3]] = new Set(parentWays[added[i3]]);
+          parentWays[added[i3]].add(entity.id);
+        }
+      } else if (type2 === "relation") {
+        var oldentityMemberIDs = oldentity ? oldentity.members.map(function(m2) {
+          return m2.id;
+        }) : [];
+        var entityMemberIDs = entity ? entity.members.map(function(m2) {
+          return m2.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 (i3 = 0; i3 < removed.length; i3++) {
+          parentRels[removed[i3]] = new Set(parentRels[removed[i3]]);
+          parentRels[removed[i3]].delete(oldentity.id);
+        }
+        for (i3 = 0; i3 < added.length; i3++) {
+          parentRels[added[i3]] = new Set(parentRels[added[i3]]);
+          parentRels[added[i3]].add(entity.id);
+        }
       }
-    }
-    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;
+    },
+    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 i3 = 0; i3 < arguments.length; i3++) {
+        arguments[i3].call(graph, graph);
       }
-      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;
-        }
-        prestep = step;
+      if (this.frozen) graph.frozen = true;
+      return graph;
+    },
+    // Obliterates any existing entities
+    load: function(entities) {
+      var base = this.base();
+      this.entities = Object.create(base.entities);
+      for (var i3 in entities) {
+        this.entities[i3] = entities[i3];
+        this._updateCalculated(base.entities[i3], this.entities[i3]);
       }
-      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 rescale() {
-      var i2 = -1;
-      domain2 = new Array(n2);
-      while (++i2 < n2)
-        domain2[i2] = ((i2 + 1) * x12 - (i2 - n2) * x05) / (n2 + 1);
-      return scale;
+      return this;
     }
-    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 reset(selection2) {
-      selection2.style("stroke-opacity", null).style("stroke-width", null).style("fill-opacity", null).style("r", null);
+  // modules/osm/intersection.js
+  function osmTurn(turn) {
+    if (!(this instanceof osmTurn)) {
+      return new osmTurn(turn);
     }
-    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"
-        );
+    Object.assign(this, turn);
+  }
+  function osmIntersection(graph, startVertexId, maxDistance) {
+    maxDistance = maxDistance || 30;
+    var vgraph = coreGraph();
+    var i3, j2, k2;
+    function memberOfRestriction(entity) {
+      return graph.parentRelations(entity).some(function(r2) {
+        return r2.isRestriction();
       });
     }
-    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);
-        } else {
-          opacity = parseFloat(s.style("stroke-opacity") || 0.7);
-          width = parseFloat(s.style("stroke-width") || 10);
-        }
-        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 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,
+        "busway": true,
+        "road": true,
+        "track": true
+      };
+      return roads[way2.tags.highway];
     }
-    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);
-      }
-      var didCallNextRun = false;
-      _selected.transition().duration(duration).call(setAnimationParams, fromTo).on("end", function() {
-        if (!didCallNextRun) {
-          surface.call(run, toFrom);
-          didCallNextRun = true;
+    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 (i3 = 0; i3 < checkWays.length; i3++) {
+        way = checkWays[i3];
+        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 (k2 = 0; k2 < parents.length; k2++) {
+            parent = parents[k2];
+            if (parent === way) continue;
+            if (ways.indexOf(parent) !== -1) continue;
+            if (!isRoad(parent)) continue;
+            hasParents = true;
+            break;
+          }
+          if (hasParents) {
+            checkVertices.push(node);
+          }
         }
-        if (!select_default2(this).classed("selected")) {
-          reset(select_default2(this));
+      }
+      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));
+          }
         }
       });
+    });
+    ways.forEach(function(w2) {
+      var way2 = vgraph.entity(w2.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(v2) {
+      var splitAll = actionSplit([v2.id]).keepHistoryOn("first");
+      if (!splitAll.disabled(vgraph)) {
+        splitAll.ways(vgraph).forEach(function(way2) {
+          var splitOne = actionSplit([v2.id]).limitWays([way2.id]).keepHistoryOn("first");
+          actions.push(splitOne);
+          vgraph = splitOne(vgraph);
+        });
+      }
+    });
+    osmEntity.id.next.way = origCount;
+    vertexIds = vertices.map(function(v2) {
+      return v2.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(v2) {
+      return v2.id;
+    });
+    wayIds = ways.map(function(w2) {
+      return w2.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
+      });
     }
-    function behavior(surface) {
-      _done = false;
-      _timer = timer(function() {
-        if (surface.selectAll(selector).empty()) {
-          return false;
+    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 (i3 = 0; i3 < checkVertices.length; i3++) {
+        var vertexId = checkVertices[i3];
+        vertex = vgraph.hasEntity(vertexId);
+        if (!vertex) {
+          if (vertexIds.indexOf(vertexId) !== -1) {
+            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
+          }
+          removeVertexIds.push(vertexId);
+          continue;
         }
-        surface.call(run, "from");
-        _timer.stop();
-        return true;
-      }, 20);
-    }
-    behavior.restartIfNeeded = function(surface) {
-      if (_selected.empty()) {
-        surface.call(run, "from");
-        if (_timer) {
-          _timer.stop();
+        parents = vgraph.parentWays(vertex);
+        if (parents.length < 3) {
+          if (vertexIds.indexOf(vertexId) !== -1) {
+            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
+          }
+        }
+        if (parents.length === 2) {
+          var a2 = parents[0];
+          var b2 = parents[1];
+          var aIsLeaf = a2 && !a2.__via;
+          var bIsLeaf = b2 && !b2.__via;
+          var leaf, survivor;
+          if (aIsLeaf && !bIsLeaf) {
+            leaf = a2;
+            survivor = b2;
+          } else if (!aIsLeaf && bIsLeaf) {
+            leaf = b2;
+            survivor = a2;
+          }
+          if (leaf && survivor) {
+            survivor = withMetadata(survivor, vertexIds);
+            vgraph = vgraph.replace(survivor).remove(leaf);
+            removeWayIds.push(leaf.id);
+            keepGoing = true;
+          }
+        }
+        parents = vgraph.parentWays(vertex);
+        if (parents.length < 2) {
+          if (vertexIds.indexOf(vertexId) !== -1) {
+            vertexIds.splice(vertexIds.indexOf(vertexId), 1);
+          }
+          removeVertexIds.push(vertexId);
+          keepGoing = true;
+        }
+        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 intersection2 = {
+      graph: vgraph,
+      actions,
+      vertices,
+      ways
     };
-    behavior.off = function() {
-      _done = true;
-      if (_timer) {
-        _timer.stop();
+    intersection2.turns = function(fromWayId, maxViaWay) {
+      if (!fromWayId) return [];
+      if (!maxViaWay) maxViaWay = 0;
+      var vgraph2 = intersection2.graph;
+      var keyVertexIds = intersection2.vertices.map(function(v2) {
+        return v2.id;
+      });
+      var start2 = vgraph2.entity(fromWayId);
+      if (!start2 || !(start2.__from || start2.__via)) return [];
+      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 i4, j3;
+        var parents2 = vgraph2.parentWays(entity);
+        var nextWays = [];
+        for (i4 = 0; i4 < parents2.length; i4++) {
+          var way2 = parents2[i4];
+          if (way2.__oneWay && way2.nodes[0] !== entity.id) continue;
+          if (currPath.indexOf(way2.id) !== -1 && currPath.length >= 3) continue;
+          var restrict = null;
+          for (j3 = 0; j3 < currRestrictions.length; j3++) {
+            var restriction = currRestrictions[j3];
+            var f2 = restriction.memberByRole("from");
+            var v2 = restriction.membersByRole("via");
+            var t2 = 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 (t2.id === way2.id) {
+              if (v2.length === 1 && v2[0].type === "node") {
+                matchesViaTo = v2[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
+              } else {
+                var pathVias = [];
+                for (k2 = 2; k2 < currPath.length; k2 += 2) {
+                  pathVias.push(currPath[k2]);
+                }
+                var restrictionVias = [];
+                for (k2 = 0; k2 < v2.length; k2++) {
+                  if (v2[k2].type === "way") {
+                    restrictionVias.push(v2[k2].id);
+                  }
+                }
+                var diff = utilArrayDifference(pathVias, restrictionVias);
+                matchesViaTo = !diff.length;
+              }
+            } else if (isOnly) {
+              for (k2 = 0; k2 < v2.length; k2++) {
+                if (v2[k2].type === "way" && v2[k2].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 });
+        }
+        nextWays.forEach(function(nextWay) {
+          step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
+        });
+      }
+      function stepWay(entity, currPath, currRestrictions, matchedRestriction) {
+        var i4;
+        if (currPath.length >= 3) {
+          var turnPath = currPath.slice();
+          if (matchedRestriction && matchedRestriction.direct === false) {
+            for (i4 = 0; i4 < turnPath.length; i4++) {
+              if (turnPath[i4] === matchedRestriction.from) {
+                turnPath = turnPath.slice(i4);
+                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;
+        }
+        if (matchedRestriction && matchedRestriction.end) return;
+        var n1 = vgraph2.entity(entity.first());
+        var n22 = vgraph2.entity(entity.last());
+        var dist = geoSphericalDistance(n1.loc, n22.loc);
+        var nextNodes = [];
+        if (currPath.length > 1) {
+          if (dist > maxDistance) return;
+          if (!entity.__via) return;
+        }
+        if (!entity.__oneWay && // bidirectional..
+        keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
+        currPath.indexOf(n1.id) === -1) {
+          nextNodes.push(n1);
+        }
+        if (keyVertexIds.indexOf(n22.id) !== -1 && // key vertex..
+        currPath.indexOf(n22.id) === -1) {
+          nextNodes.push(n22);
+        }
+        nextNodes.forEach(function(nextNode) {
+          var fromRestrictions = vgraph2.parentRelations(entity).filter(function(r2) {
+            if (!r2.isRestriction()) return false;
+            var f2 = r2.memberByRole("from");
+            if (!f2 || f2.id !== entity.id) return false;
+            var isOnly = /^only_/.test(r2.tags.restriction);
+            if (!isOnly) return true;
+            var isOnlyVia = false;
+            var v2 = r2.membersByRole("via");
+            if (v2.length === 1 && v2[0].type === "node") {
+              isOnlyVia = v2[0].id === nextNode.id;
+            } else {
+              for (var i5 = 0; i5 < v2.length; i5++) {
+                if (v2[i5].type !== "way") continue;
+                var viaWay = vgraph2.entity(v2[i5].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);
+          }
+        }
+        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];
+        }
       }
-      _selected.interrupt().call(reset);
     };
-    return behavior;
+    return intersection2;
   }
-
-  // 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 {
-        context.ui().flash.duration(2e3).iconName("#iD-operation-" + _operation.id).iconClass("operation").label(_operation.annotation() || _operation.title)();
-        if (_operation.point)
-          _operation.point(null);
-        _operation();
-      }
+  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;
     }
-    function behavior() {
-      if (_operation && _operation.available()) {
-        context.keybinding().on(_operation.keys, keypress);
-      }
-      return behavior;
+    if (fromNode === toNode) {
+      return "no_u_turn";
     }
-    behavior.off = function() {
-      context.keybinding().off(_operation.keys);
-    };
-    behavior.which = function(_) {
-      if (!arguments.length)
-        return _operation;
-      _operation = _;
-      return behavior;
-    };
-    return behavior;
+    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/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);
+  // 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 operation = function() {
-      if (!_actions.length)
-        return;
-      var combinedAction = function(graph, t) {
-        _actions.forEach(function(action) {
-          if (!action.disabled(graph)) {
-            graph = action(graph, t);
+    var action = function(graph) {
+      var entities = groupEntities(graph);
+      var polygons = entities.multipolygon.reduce(function(polygons2, m2) {
+        return polygons2.concat(osmJoinWays(m2.members, graph));
+      }, []).concat(entities.closedWay.map(function(d2) {
+        var member = [{ id: d2.id }];
+        member.nodes = graph.childNodes(d2);
+        return member;
+      }));
+      var contained = polygons.map(function(w2, i3) {
+        return polygons.map(function(d2, n3) {
+          if (i3 === n3) return null;
+          return geoPolygonContainsPolygon(
+            d2.nodes.map(function(n4) {
+              return n4.loc;
+            }),
+            w2.nodes.map(function(n4) {
+              return n4.loc;
+            })
+          );
+        });
+      });
+      var members = [];
+      var outer = true;
+      while (polygons.length) {
+        extractUncontained(polygons);
+        polygons = polygons.filter(isContained);
+        contained = contained.filter(isContained).map(filterContained);
+      }
+      function isContained(d2, i3) {
+        return contained[i3].some(function(val) {
+          return val;
+        });
+      }
+      function filterContained(d2) {
+        return d2.filter(isContained);
+      }
+      function extractUncontained(polygons2) {
+        polygons2.forEach(function(d2, i3) {
+          if (!isContained(d2, i3)) {
+            d2.forEach(function(member) {
+              members.push({
+                type: "way",
+                id: member.id,
+                role: outer ? "outer" : "inner"
+              });
+            });
           }
         });
-        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";
+        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(m2) {
+        if (m2.id !== relation.id) {
+          relation = relation.mergeTags(m2.tags);
+          graph = graph.remove(m2);
         }
-        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";
+      });
+      entities.closedWay.forEach(function(way) {
+        function isThisOuter(m2) {
+          return m2.id === way.id && m2.role !== "inner";
+        }
+        if (members.some(isThisOuter)) {
+          relation = relation.mergeTags(way.tags);
+          graph = graph.replace(way.update({ tags: {} }));
+        }
+      });
+      return graph.replace(relation.update({
+        members,
+        tags: utilObjectOmit(relation.tags, ["area"])
+      }));
+    };
+    action.disabled = function(graph) {
+      var entities = groupEntities(graph);
+      if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
+        return "not_eligible";
       }
-      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 (!entities.multipolygon.every(function(r2) {
+        return r2.isComplete(graph);
+      })) {
+        return "incomplete_relation";
+      }
+      if (!entities.multipolygon.length) {
+        var sharedMultipolygons = [];
+        entities.closedWay.forEach(function(way, i3) {
+          if (i3 === 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";
         }
-        return false;
+      } else if (entities.closedWay.some(function(way) {
+        return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
+      })) {
+        return "not_eligible";
       }
     };
-    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;
+    return action;
   }
 
-  // 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";
-    }
-    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 ? "+" : "");
+  // 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 {
-        result += code[i2];
+        equivalenceClasses[item] = [j2];
       }
     }
-    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--;
+    const NULLRESULT = { buffer1index: -1, buffer2index: -1, chain: null };
+    let candidates = [NULLRESULT];
+    for (let i3 = 0; i3 < buffer1.length; i3++) {
+      const item = buffer1[i3];
+      const buffer2indices = equivalenceClasses[item] || [];
+      let r2 = 0;
+      let c2 = candidates[0];
+      for (let jx = 0; jx < buffer2indices.length; jx++) {
+        const j2 = buffer2indices[jx];
+        let s2;
+        for (s2 = r2; s2 < candidates.length; s2++) {
+          if (candidates[s2].buffer2index < j2 && (s2 === candidates.length - 1 || candidates[s2 + 1].buffer2index > j2)) {
+            break;
+          }
+        }
+        if (s2 < candidates.length) {
+          const newCandidate = { buffer1index: i3, buffer2index: j2, chain: candidates[s2] };
+          if (r2 === candidates.length) {
+            candidates.push(c2);
           } 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;
+            candidates[r2] = c2;
+          }
+          r2 = s2 + 1;
+          c2 = newCandidate;
+          if (r2 === candidates.length) {
+            break;
           }
-          nextSelectedID = nodes2[i2];
-          nextSelectedLoc = context.entity(nextSelectedID).loc;
         }
       }
-      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));
+      candidates[r2] = c2;
+    }
+    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(a2, o2, b2) {
+    let hunks = [];
+    function addHunk(h2, ab) {
+      hunks.push({
+        ab,
+        oStart: h2.buffer1[0],
+        oLength: h2.buffer1[1],
+        // length of o to remove
+        abStart: h2.buffer2[0],
+        abLength: h2.buffer2[1]
+        // length of a/b to insert
+        // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
+      });
+    }
+    diffIndices(o2, a2).forEach((item) => addHunk(item, "a"));
+    diffIndices(o2, b2).forEach((item) => addHunk(item, "b"));
+    hunks.sort((x2, y2) => x2.oStart - y2.oStart);
+    let results = [];
+    let currOffset = 0;
+    function advanceTo(endOffset) {
+      if (endOffset > currOffset) {
+        results.push({
+          stable: true,
+          buffer: "o",
+          bufferStart: currOffset,
+          bufferLength: endOffset - currOffset,
+          bufferContent: o2.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" ? a2 : b2;
+          results.push({
+            stable: true,
+            buffer: hunk.ab,
+            bufferStart: hunk.abStart,
+            bufferLength: hunk.abLength,
+            bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
+          });
         }
       } else {
-        context.enter(modeBrowse(context));
+        let bounds = {
+          a: [a2.length, -1, o2.length, -1],
+          b: [b2.length, -1, o2.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 b3 = bounds[hunk.ab];
+          b3[0] = Math.min(abStart, b3[0]);
+          b3[1] = Math.max(abEnd, b3[1]);
+          b3[2] = Math.min(oStart, b3[2]);
+          b3[3] = Math.max(oEnd, b3[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: a2.slice(aStart, aEnd),
+          oStart: regionStart,
+          oLength: regionEnd - regionStart,
+          oContent: o2.slice(regionStart, regionEnd),
+          bStart,
+          bLength: bEnd - bStart,
+          bContent: b2.slice(bStart, bEnd)
+        };
+        results.push(result);
       }
+      currOffset = regionEnd;
+    }
+    advanceTo(o2.length);
+    return results;
+  }
+  function diff3Merge(a2, o2, b2, options2) {
+    let defaults = {
+      excludeFalseConflicts: true,
+      stringSeparator: /\s+/
     };
-    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";
+    options2 = Object.assign(defaults, options2);
+    if (typeof a2 === "string") a2 = a2.split(options2.stringSeparator);
+    if (typeof o2 === "string") o2 = o2.split(options2.stringSeparator);
+    if (typeof b2 === "string") b2 = b2.split(options2.stringSeparator);
+    let results = [];
+    const regions = diff3MergeRegions(a2, o2, b2);
+    let okBuffer = [];
+    function flushOk() {
+      if (okBuffer.length) {
+        results.push({ ok: okBuffer });
       }
-      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);
+      okBuffer = [];
+    }
+    function isFalseConflict(a3, b3) {
+      if (a3.length !== b3.length) return false;
+      for (let i3 = 0; i3 < a3.length; i3++) {
+        if (a3[i3] !== b3[i3]) return false;
+      }
+      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
+            }
           });
-          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;
+    });
+    flushOk();
+    return results;
+  }
+
+  // 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(d2) {
+      return typeof formatUser === "function" ? formatUser(d2) : (0, import_lodash2.escape)(d2);
+    }
+    function mergeLocation(remote, target) {
+      function pointEqual(a2, b2) {
+        var epsilon3 = 1e-6;
+        return Math.abs(a2[0] - b2[0]) < epsilon3 && Math.abs(a2[1] - b2[1]) < epsilon3;
       }
-      function incompleteRelation(id2) {
-        var entity = context.entity(id2);
-        return entity.type === "relation" && !entity.isComplete(context.graph());
+      if (_option === "force_local" || pointEqual(target.loc, remote.loc)) {
+        return target;
       }
-      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;
+      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 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 o2 = base.nodes || [];
+      var a2 = target.nodes || [];
+      var b2 = remote.nodes || [];
+      var nodes = [];
+      var hunks = diff3Merge(a2, o2, b2, { excludeFalseConflicts: true });
+      for (var i3 = 0; i3 < hunks.length; i3++) {
+        var hunk = hunks[i3];
+        if (hunk.ok) {
+          nodes.push.apply(nodes, hunk.ok);
+        } else {
+          var c2 = hunk.conflict;
+          if ((0, import_fast_deep_equal.default)(c2.o, c2.a)) {
+            nodes.push.apply(nodes, c2.b);
+          } else if ((0, import_fast_deep_equal.default)(c2.o, c2.b)) {
+            nodes.push.apply(nodes, c2.a);
+          } else {
+            _conflicts.push(_t.html("merge_remote_changes.conflict.nodelist", { user: { html: user(remote.user) } }));
+            break;
           }
         }
-        return false;
       }
-    };
-    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/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()));
+      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;
       }
-      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 ccount = _conflicts.length;
+      for (var i3 = 0; i3 < children2.length; i3++) {
+        var id3 = children2[i3];
+        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);
         }
       }
-      return null;
+      return targetWay;
     }
-    var operation = function() {
-      if (!_actions.length)
-        return;
-      var combinedAction = function(graph, t) {
-        _actions.forEach(function(action) {
-          if (!action.disabled(graph)) {
-            graph = action(graph, t);
+    function updateChildren(updates, graph) {
+      for (var i3 = 0; i3 < updates.replacements.length; i3++) {
+        graph = graph.replace(updates.replacements[i3]);
+      }
+      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 });
+      }
+      var ccount = _conflicts.length;
+      var o2 = base.tags || {};
+      var a2 = target.tags || {};
+      var b2 = remote.tags || {};
+      var keys2 = utilArrayUnion(utilArrayUnion(Object.keys(o2), Object.keys(a2)), Object.keys(b2)).filter(function(k3) {
+        return !discardTags[k3];
+      });
+      var tags = Object.assign({}, a2);
+      var changed = false;
+      for (var i3 = 0; i3 < keys2.length; i3++) {
+        var k2 = keys2[i3];
+        if (o2[k2] !== b2[k2] && a2[k2] !== b2[k2]) {
+          if (o2[k2] !== a2[k2]) {
+            _conflicts.push(_t.html(
+              "merge_remote_changes.conflict.tags",
+              { tag: k2, local: a2[k2], remote: b2[k2], user: { html: user(remote.user) } }
+            ));
+          } else {
+            if (b2.hasOwnProperty(k2)) {
+              tags[k2] = b2[k2];
+            } else {
+              delete tags[k2];
+            }
+            changed = true;
           }
-        });
-        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 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;
         }
-        return false;
       }
+      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;
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
-      return disable ? _t.append("operations.orthogonalize." + disable + "." + _amount) : _t.append("operations.orthogonalize.description." + _type + "." + _amount);
+    action.withOption = function(opt) {
+      _option = opt;
+      return action;
     };
-    operation.annotation = function() {
-      return _t("operations.orthogonalize.annotation." + _type, { n: _actions.length });
+    action.conflicts = function() {
+      return _conflicts;
     };
-    operation.id = "orthogonalize";
-    operation.keys = [_t("operations.orthogonalize.key")];
-    operation.title = _t.append("operations.orthogonalize.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    return action;
   }
 
-  // modules/operations/reflect.js
-  function operationReflectShort(context, selectedIDs) {
-    return operationReflect(context, selectedIDs, "short");
-  }
-  function operationReflectLong(context, selectedIDs) {
-    return operationReflect(context, selectedIDs, "long");
-  }
-  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";
+  // 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;
       }
-      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 cacheEntities(ids) {
+        for (var i3 = 0; i3 < ids.length; i3++) {
+          var id2 = ids[i3];
+          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;
+            }));
           }
         }
-        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);
+      function cacheIntersections(ids) {
+        function isEndpoint(way2, id3) {
+          return !way2.isClosed() && !!way2.affix(id3);
+        }
+        for (var i3 = 0; i3 < ids.length; i3++) {
+          var id2 = ids[i3];
+          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 k2 = 0; k2 < parents.length; k2++) {
+              var way = parents[k2];
+              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)
             });
-            return true;
           }
         }
-        return false;
       }
-      function incompleteRelation(id2) {
-        var entity = context.entity(id2);
-        return entity.type === "relation" && !entity.isComplete(context.graph());
+      if (!cache) {
+        cache = {};
       }
-    };
-    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;
+      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 {
-        fn = context.replace;
+        len = way.nodes.length;
+        prevIndex = movedIndex - 1;
+        nextIndex = movedIndex + 1;
       }
-      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 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 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);
+      var start2, end;
+      if (delta) {
+        start2 = projection2(cache.startLoc[nodeId]);
+        end = projection2.invert(geoVecAdd(start2, delta));
       } 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));
+        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);
+    }
+    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 i3 = 0; i3 < way.nodes.length; i3++) {
+        curr = graph.entity(way.nodes[i3]);
+        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 _pivot2;
+      return graph;
     }
-    function finish(d3_event) {
-      d3_event.stopPropagation();
-      context.replace(actionNoop(), annotation);
-      context.enter(modeSelect(context, entityIDs));
+    function unZorroIntersection(intersection2, graph) {
+      var vertex = graph.entity(intersection2.nodeId);
+      var way1 = graph.entity(intersection2.movedId);
+      var way2 = graph.entity(intersection2.unmovedId);
+      var isEP1 = intersection2.movedIsEP;
+      var isEP2 = intersection2.unmovedIsEP;
+      if (isEP1 && isEP2) return graph;
+      var nodes1 = graph.childNodes(way1).filter(function(n3) {
+        return n3 !== vertex;
+      });
+      var nodes2 = graph.childNodes(way2).filter(function(n3) {
+        return n3 !== vertex;
+      });
+      if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
+      if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
+      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 i3 = 0; i3 < maxIter; i3++) {
+          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 cancel() {
-      if (_prevGraph)
-        context.pop();
-      context.enter(modeSelect(context, entityIDs));
+    function cleanupIntersections(graph) {
+      for (var i3 = 0; i3 < cache.intersections.length; i3++) {
+        var obj = cache.intersections[i3];
+        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 undone() {
-      context.enter(modeBrowse(context));
+    function limitDelta(graph) {
+      function moveNode(loc) {
+        return geoVecAdd(projection2(loc), _delta);
+      }
+      for (var i3 = 0; i3 < cache.intersections.length; i3++) {
+        var obj = cache.intersections[i3];
+        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(n3) {
+          return moveNode(n3.loc);
+        });
+        var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
+        var unmovedPath = unmovedNodes.map(function(n3) {
+          return projection2(n3.loc);
+        });
+        var hits = geoPathIntersections(movedPath, unmovedPath);
+        for (var j2 = 0; i3 < hits.length; i3++) {
+          if (geoVecEqual(hits[j2], end)) continue;
+          var edge = geoChooseEdge(unmovedNodes, end, projection2);
+          _delta = geoVecSubtract(projection2(edge.loc), start2);
+        }
+      }
     }
-    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);
+    var action = function(graph) {
+      if (_delta[0] === 0 && _delta[1] === 0) return graph;
+      setupCache(graph);
+      if (cache.intersections.length) {
+        limitDelta(graph);
+      }
+      for (var i3 = 0; i3 < cache.nodes.length; i3++) {
+        var node = graph.entity(cache.nodes[i3]);
+        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;
     };
-    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([]);
+    action.delta = function() {
+      return _delta;
     };
-    mode.selectedIDs = function() {
-      if (!arguments.length)
-        return entityIDs;
-      return mode;
+    return action;
+  }
+
+  // modules/actions/move_member.js
+  function actionMoveMember(relationId, fromIndex, toIndex) {
+    return function(graph) {
+      return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
     };
-    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));
+  // modules/actions/move_node.js
+  function actionMoveNode(nodeID, toLoc) {
+    var action = function(graph, t2) {
+      if (t2 === null || !isFinite(t2)) t2 = 1;
+      t2 = Math.min(Math.max(+t2, 0), 1);
+      var node = graph.entity(nodeID);
+      return graph.replace(
+        node.move(geoVecInterp(node.loc, toLoc, t2))
+      );
     };
-    operation.available = function() {
-      return nodes.length >= 2;
+    action.transitionable = true;
+    return action;
+  }
+
+  // modules/actions/noop.js
+  function actionNoop() {
+    return function(graph) {
+      return graph;
     };
-    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";
+  }
+
+  // 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, t2) {
+      if (t2 === null || !isFinite(t2)) t2 = 1;
+      t2 = Math.min(Math.max(+t2, 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 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;
+      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, i3, j2;
+      for (i3 = 0; i3 < nodes.length; i3++) {
+        node = nodes[i3];
+        nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
+        points.push({ id: node.id, coord: projection2(node.loc) });
+      }
+      if (points.length === 3) {
+        for (i3 = 0; i3 < 1e3; i3++) {
+          motions = points.map(calcMotion);
+          points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
+          score = corner.dotp;
+          if (score < epsilon3) {
+            break;
+          }
+        }
+        node = graph.entity(nodes[corner.i].id);
+        loc = projection2.invert(points[corner.i].coord);
+        graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t2)));
+      } else {
+        var straights = [];
+        var simplified = [];
+        for (i3 = 0; i3 < points.length; i3++) {
+          point = points[i3];
+          var dotp = 0;
+          if (isClosed || i3 > 0 && i3 < points.length - 1) {
+            var a2 = points[(i3 - 1 + points.length) % points.length];
+            var b2 = points[(i3 + 1) % points.length];
+            dotp = Math.abs(geoOrthoNormalizedDotProduct(a2.coord, b2.coord, point.coord));
+          }
+          if (dotp > upperThreshold) {
+            straights.push(point);
+          } else {
+            simplified.push(point);
+          }
+        }
+        var bestPoints = clonePoints(simplified);
+        var originalPoints = clonePoints(simplified);
+        score = Infinity;
+        for (i3 = 0; i3 < 1e3; i3++) {
+          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(p2) {
+          return p2.coord;
+        });
+        if (isClosed) bestCoords.push(bestCoords[0]);
+        for (i3 = 0; i3 < bestPoints.length; i3++) {
+          point = bestPoints[i3];
+          if (!geoVecEqual(originalPoints[i3].coord, point.coord)) {
+            node = graph.entity(point.id);
+            loc = projection2.invert(point.coord);
+            graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t2)));
+          }
+        }
+        for (i3 = 0; i3 < straights.length; i3++) {
+          point = straights[i3];
+          if (nodeCount[point.id] > 1) continue;
+          node = graph.entity(point.id);
+          if (t2 === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
+            graph = actionDeleteNode(node.id)(graph);
+          } else {
+            var choice = geoVecProject(point.coord, bestCoords);
+            if (choice) {
+              loc = projection2.invert(choice.target);
+              graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t2)));
+            }
           }
         }
-        return false;
       }
-      function incompleteRelation(id2) {
-        var entity = context.entity(id2);
-        return entity.type === "relation" && !entity.isComplete(context.graph());
+      return graph;
+      function clonePoints(array2) {
+        return array2.map(function(p2) {
+          return { id: p2.id, coord: [p2.coord[0], p2.coord[1]] };
+        });
+      }
+      function calcMotion(point2, i4, array2) {
+        if (!isClosed && (i4 === 0 || i4 === array2.length - 1)) return [0, 0];
+        if (nodeCount[array2[i4].id] > 1) return [0, 0];
+        var a3 = array2[(i4 - 1 + array2.length) % array2.length].coord;
+        var origin = point2.coord;
+        var b3 = array2[(i4 + 1) % array2.length].coord;
+        var p2 = geoVecSubtract(a3, origin);
+        var q2 = geoVecSubtract(b3, origin);
+        var scale = 2 * Math.min(geoVecLength(p2), geoVecLength(q2));
+        p2 = geoVecNormalize(p2);
+        q2 = geoVecNormalize(q2);
+        var dotp2 = p2[0] * q2[0] + p2[1] * q2[1];
+        var val = Math.abs(dotp2);
+        if (val < lowerThreshold) {
+          corner.i = i4;
+          corner.dotp = val;
+          var vec = geoVecNormalize(geoVecAdd(p2, q2));
+          return geoVecScale(vec, 0.1 * dotp2 * scale);
+        }
+        return [0, 0];
       }
     };
-    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;
+    function nodeSubset(nodes, vertexID2, isClosed) {
+      var first = isClosed ? 0 : 1;
+      var last = isClosed ? nodes.length : nodes.length - 1;
+      for (var i3 = first; i3 < last; i3++) {
+        if (nodes[i3].id === vertexID2) {
+          return [
+            nodes[(i3 - 1 + nodes.length) % nodes.length],
+            nodes[i3],
+            nodes[(i3 + 1) % nodes.length]
+          ];
+        }
       }
-      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);
+      return [];
     }
-    function stopNudge() {
-      if (_nudgeInterval) {
-        window.clearInterval(_nudgeInterval);
-        _nudgeInterval = null;
+    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";
       }
-    }
-    function move() {
-      doMove();
-      var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
-      if (nudge) {
-        startNudge(nudge);
+      var coords = nodes.map(function(n3) {
+        return projection2(n3.loc);
+      });
+      var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon3, threshold, allowStraightAngles);
+      if (score === null) {
+        return "not_squarish";
+      } else if (score === 0) {
+        return "square_enough";
       } else {
-        stopNudge();
+        return false;
       }
-    }
-    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));
-      }
-      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);
-    };
-    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;
+    action.transitionable = true;
+    return action;
   }
 
-  // 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);
+  // 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);
       });
-      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);
+      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" });
         });
-        if (!parentCopied) {
-          newIDs.push(newEntity.id);
-        }
       }
-      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"));
+      members.push({ id: toWay.id, type: "way", role: "to" });
+      return graph.replace(osmRelation({
+        id: restrictionID,
+        tags: {
+          type: "restriction",
+          restriction: restrictionType
+        },
+        members
+      }));
     };
-    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);
-      };
-    };
-    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];
-      }
-      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]);
-        }
-      }
-      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();
-        }
-        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);
+  // 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);
           }
-        };
+        });
       }
-      selection2.on(_pointerPrefix + "down.drag" + _selector, delegate);
-    }
-    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;
+      return graph.revert(id2);
     };
-    behavior.surface = function(_) {
-      if (!arguments.length)
-        return _surface;
-      _surface = _;
-      return behavior;
+    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 utilRebind(behavior, dispatch10, "on");
+    return action;
   }
 
-  // modules/modes/drag_node.js
-  function modeDragNode(context) {
-    var mode = {
-      id: "drag-node",
-      button: "browse"
+  // 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)));
+        });
+      });
     };
-    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/actions/straighten_nodes.js
+  function actionStraightenNodes(nodeIDs, projection2) {
+    function positionAlongWay(a2, o2, b2) {
+      return geoVecDot(a2, b2, o2) / geoVecDot(b2, b2, o2);
     }
-    function stopNudge() {
-      if (_nudgeInterval) {
-        window.clearInterval(_nudgeInterval);
-        _nudgeInterval = null;
+    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];
     }
-    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");
-        }
+    var action = function(graph, t2) {
+      if (t2 === null || !isFinite(t2)) t2 = 1;
+      t2 = Math.min(Math.max(+t2, 0), 1);
+      var nodes = nodeIDs.map(function(id2) {
+        return graph.entity(id2);
+      });
+      var points = nodes.map(function(n3) {
+        return projection2(n3.loc);
+      });
+      var endpoints = getEndpoints(points);
+      var startPoint = endpoints[0];
+      var endPoint = endpoints[1];
+      for (var i3 = 0; i3 < points.length; i3++) {
+        var node = nodes[i3];
+        var point = points[i3];
+        var u2 = positionAlongWay(point, startPoint, endPoint);
+        var point2 = geoVecInterp(startPoint, endPoint, u2);
+        var loc2 = projection2.invert(point2);
+        graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t2)));
       }
-      return _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);
-    }
-    function keydown(d3_event) {
-      if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
-        if (context.surface().classed("nope")) {
-          context.surface().classed("nope-suppressed", true);
+      return graph;
+    };
+    action.disabled = function(graph) {
+      var nodes = nodeIDs.map(function(id2) {
+        return graph.entity(id2);
+      });
+      var points = nodes.map(function(n3) {
+        return projection2(n3.loc);
+      });
+      var endpoints = getEndpoints(points);
+      var startPoint = endpoints[0];
+      var endPoint = endpoints[1];
+      var maxDistance = 0;
+      for (var i3 = 0; i3 < points.length; i3++) {
+        var point = points[i3];
+        var u2 = positionAlongWay(point, startPoint, endPoint);
+        var p2 = geoVecInterp(startPoint, endPoint, u2);
+        var dist = geoVecLength(p2, point);
+        if (!isNaN(dist) && dist > maxDistance) {
+          maxDistance = dist;
         }
-        context.surface().classed("nope", false).classed("nope-disabled", true);
       }
-    }
-    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 (maxDistance < 1e-4) {
+        return "straight_enough";
       }
+    };
+    action.transitionable = true;
+    return action;
+  }
+
+  // modules/actions/straighten_way.js
+  function actionStraightenWay(selectedIDs, projection2) {
+    function positionAlongWay(a2, o2, b2) {
+      return geoVecDot(a2, b2, o2) / geoVecDot(b2, b2, o2);
     }
-    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"))();
+    function allNodes(graph) {
+      var nodes = [];
+      var startNodes = [];
+      var endNodes = [];
+      var remainingWays = [];
+      var selectedWays = selectedIDs.filter(function(w2) {
+        return graph.entity(w2).type === "way";
+      });
+      var selectedNodes = selectedIDs.filter(function(n3) {
+        return graph.entity(n3).type === "node";
+      });
+      for (var i3 = 0; i3 < selectedWays.length; i3++) {
+        var way = graph.entity(selectedWays[i3]);
+        nodes = way.nodes.slice(0);
+        remainingWays.push(nodes);
+        startNodes.push(nodes[0]);
+        endNodes.push(nodes[nodes.length - 1]);
+      }
+      startNodes = startNodes.filter(function(n3) {
+        return startNodes.indexOf(n3) === startNodes.lastIndexOf(n3);
+      });
+      endNodes = endNodes.filter(function(n3) {
+        return endNodes.indexOf(n3) === endNodes.lastIndexOf(n3);
+      });
+      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();
         }
-        return drag.cancel();
+        nodes = nodes.concat(nextWay);
+        currNode = nodes[nodes.length - 1];
       }
-      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());
+      if (selectedNodes.length === 2) {
+        var startNodeIdx = nodes.indexOf(selectedNodes[0]);
+        var endNodeIdx = nodes.indexOf(selectedNodes[1]);
+        var sortedStartEnd = [startNodeIdx, endNodeIdx];
+        sortedStartEnd.sort(function(a2, b2) {
+          return a2 - b2;
+        });
+        nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
       }
-      _activeEntity = entity;
-      _startLoc = entity.loc;
-      hover.ignoreVertex(entity.geometry(context.graph()) === "vertex");
-      context.surface().selectAll("." + _activeEntity.id).classed("active", true);
-      context.enter(mode);
+      return nodes.map(function(n3) {
+        return graph.entity(n3);
+      });
     }
-    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 shouldKeepNode(node, graph) {
+      return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
     }
-    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;
+    var action = function(graph, t2) {
+      if (t2 === null || !isFinite(t2)) t2 = 1;
+      t2 = Math.min(Math.max(+t2, 0), 1);
+      var nodes = allNodes(graph);
+      var points = nodes.map(function(n3) {
+        return projection2(n3.loc);
+      });
+      var startPoint = points[0];
+      var endPoint = points[points.length - 1];
+      var toDelete = [];
+      var i3;
+      for (i3 = 1; i3 < points.length - 1; i3++) {
+        var node = nodes[i3];
+        var point = points[i3];
+        if (t2 < 1 || shouldKeepNode(node, graph)) {
+          var u2 = positionAlongWay(point, startPoint, endPoint);
+          var p2 = geoVecInterp(startPoint, endPoint, u2);
+          var loc2 = projection2.invert(p2);
+          graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t2)));
+        } else {
+          if (toDelete.indexOf(node) === -1) {
+            toDelete.push(node);
           }
         }
       }
-      context.replace(
-        actionMoveNode(entity.id, loc)
-      );
-      var isInvalid = false;
-      if (target) {
-        isInvalid = hasRelationConflict(entity, target, edge, context.graph());
+      for (i3 = 0; i3 < toDelete.length; i3++) {
+        graph = actionDeleteNode(toDelete[i3].id)(graph);
       }
-      if (!isInvalid) {
-        isInvalid = hasInvalidGeometry(entity, context.graph());
+      return graph;
+    };
+    action.disabled = function(graph) {
+      var nodes = allNodes(graph);
+      var points = nodes.map(function(n3) {
+        return projection2(n3.loc);
+      });
+      var startPoint = points[0];
+      var endPoint = points[points.length - 1];
+      var threshold = 0.2 * geoVecLength(startPoint, endPoint);
+      var i3;
+      if (threshold === 0) {
+        return "too_bendy";
       }
-      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("")();
+      var maxDistance = 0;
+      for (i3 = 1; i3 < points.length - 1; i3++) {
+        var point = points[i3];
+        var u2 = positionAlongWay(point, startPoint, endPoint);
+        var p2 = geoVecInterp(startPoint, endPoint, u2);
+        var dist = geoVecLength(p2, point);
+        if (isNaN(dist) || dist > threshold) {
+          return "too_bendy";
+        } else if (dist > maxDistance) {
+          maxDistance = dist;
         }
       }
-      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;
-    }
-    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 keepingAllNodes = nodes.every(function(node, i4) {
+        return i4 === 0 || i4 === 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";
       }
-      var ids = [entity.id, target.id];
-      return actionConnect(ids).disabled(testGraph);
-    }
-    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";
-              }
+    };
+    action.transitionable = true;
+    return action;
+  }
+
+  // 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, t2) {
+      if (t2 === null || !isFinite(t2)) t2 = 1;
+      t2 = Math.min(Math.max(+t2, 0), 1);
+      var nodes = utilGetAllNodes(reflectIds, graph);
+      var points = nodes.map(function(n3) {
+        return projection2(n3.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 p3, q3;
+      var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
+      if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
+        p3 = p1;
+        q3 = q1;
+      } else {
+        p3 = p2;
+        q3 = q2;
+      }
+      var dx = q3[0] - p3[0];
+      var dy = q3[1] - p3[1];
+      var a2 = (dx * dx - dy * dy) / (dx * dx + dy * dy);
+      var b2 = 2 * dx * dy / (dx * dx + dy * dy);
+      for (var i3 = 0; i3 < nodes.length; i3++) {
+        var node = nodes[i3];
+        var c2 = projection2(node.loc);
+        var c22 = [
+          a2 * (c2[0] - p3[0]) + b2 * (c2[1] - p3[1]) + p3[0],
+          b2 * (c2[0] - p3[0]) - a2 * (c2[1] - p3[1]) + p3[1]
+        ];
+        var loc2 = projection2.invert(c22);
+        node = node.move(geoVecInterp(node.loc, loc2, t2));
+        graph = graph.replace(node);
+      }
+      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;
             }
-            rings[k].coords = nodes.map(function(n2) {
-              return n2.loc;
-            });
+            vals.splice(oldIndex, 1);
+            tags[oldTagKey] = vals.join(";");
           }
-          for (k = 0; k < rings.length; k++) {
-            if (k === activeIndex)
+        }
+      }
+      if (replaceTags) {
+        for (var replaceKey in replaceTags) {
+          var replaceValue = replaceTags[replaceKey];
+          if (replaceValue === "*") {
+            if (tags[replaceKey] && tags[replaceKey] !== "no") {
               continue;
-            if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
-              return "multipolygonRing";
+            } 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;
             }
           }
         }
-        if (activeIndex === null) {
-          nodes = parent.nodes.map(function(nodeID) {
-            return graph.entity(nodeID);
+      }
+      return graph.replace(entity.update({ tags }));
+    };
+  }
+
+  // modules/behavior/edit.js
+  function behaviorEdit(context) {
+    function behavior() {
+      context.map().minzoom(context.minEditableZoom());
+    }
+    behavior.off = function() {
+      context.map().minzoom(0);
+    };
+    return behavior;
+  }
+
+  // modules/behavior/hover.js
+  function behaviorHover(context) {
+    var dispatch14 = 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);
+        dispatch14.call("hover", this, null);
+      }
+    }
+    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);
+        dispatch14.call("hover", this, _targets);
+      }
+    }
+    function behavior(selection2) {
+      _selection = selection2;
+      _targets = [];
+      if (_initialNodeID) {
+        _newNodeId = _initialNodeID;
+        _initialNodeID = null;
+      } else {
+        _newNodeId = null;
+      }
+      _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;
+      }
+      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);
+        }
+      }
+      function allowsVertex(d2) {
+        return d2.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d2, context.graph());
+      }
+      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";
           });
-          if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
-            return parent.geometry(graph);
+          _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 i3 in targets) {
+          var datum2 = targets[i3];
+          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;
+              }
+            }
           }
         }
+        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);
+        }
+        dispatch14.call("hover", this, !suppressed && targets);
       }
-      return false;
     }
-    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);
+    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, dispatch14, "on");
+  }
+
+  // modules/behavior/draw.js
+  var _disableSpace = false;
+  var _lastSpace = null;
+  function behaviorDraw(context) {
+    var dispatch14 = 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 {
-        stopNudge();
+        element = d3_event.target;
       }
+      var d2 = element.__data__;
+      return d2 && d2.properties && d2.properties.target ? d2 : {};
     }
-    function end(d3_event, entity) {
-      if (_isCancelled)
+    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)
+      };
+      dispatch14.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;
+          dispatch14.call("downcancel", this);
+        }
+      }
+      if (d3_event.pointerType && d3_event.pointerType !== "mouse" || d3_event.buttons || _downPointer) return;
+      if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== "mouse" && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
+      _lastMouse = d3_event;
+      dispatch14.call("move", this, d3_event, datum2(d3_event));
+    }
+    function pointercancel(d3_event) {
+      if (_downPointer && _downPointer.id === (d3_event.pointerId || "mouse")) {
+        if (!_downPointer.isCancelled) {
+          dispatch14.call("downcancel", this);
+        }
+        _downPointer = null;
+      }
+    }
+    function mouseenter() {
+      _mouseLeave = false;
+    }
+    function mouseleave() {
+      _mouseLeave = true;
+    }
+    function allowsVertex(d2) {
+      return d2.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d2, context.graph());
+    }
+    function click(d3_event, loc) {
+      var d2 = datum2(d3_event);
+      var target = d2 && d2.properties && d2.properties.entity;
+      var mode = context.mode();
+      if (target && target.type === "node" && allowsVertex(target)) {
+        dispatch14.call("clickNode", this, target, d2);
         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)
+      } 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]];
+          dispatch14.call("clickWay", this, choice.loc, edge, d2);
+          return;
+        }
+      } else if (mode.id !== "add-point" || mode.preset.matchGeometry("point")) {
+        var locLatLng = context.projection.invert(loc);
+        dispatch14.call("click", this, locLatLng, d2);
       }
-      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));
+    }
+    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;
         }
       }
+      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 _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 backspace(d3_event) {
+      d3_event.preventDefault();
+      dispatch14.call("undo");
     }
-    function cancel() {
-      drag.cancel();
-      context.enter(modeBrowse(context));
+    function del(d3_event) {
+      d3_event.preventDefault();
+      dispatch14.call("cancel");
     }
-    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() {
+    function ret(d3_event) {
+      d3_event.preventDefault();
+      dispatch14.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(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;
+      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);
     };
-    mode.restoreSelectedIDs = function(_) {
-      if (!arguments.length)
-        return _restoreSelectedIDs;
-      _restoreSelectedIDs = _;
-      return mode;
+    behavior.hover = function() {
+      return _hover;
     };
-    mode.behavior = drag;
-    return mode;
+    return utilRebind(behavior, dispatch14, "on");
   }
 
-  // modules/services/keepRight.js
-  var import_rbush = __toESM(require_rbush_min());
+  // modules/behavior/breathe.js
+  var import_fast_deep_equal2 = __toESM(require_fast_deep_equal());
 
-  // 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-scale/src/init.js
+  function initRange(domain, range3) {
+    switch (arguments.length) {
+      case 0:
+        break;
+      case 1:
+        this.range(domain);
+        break;
+      default:
+        this.range(range3).domain(domain);
+        break;
+    }
+    return this;
   }
 
-  // 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-scale/src/constant.js
+  function constants(x2) {
+    return function() {
+      return x2;
+    };
   }
 
-  // node_modules/d3-fetch/src/xml.js
-  function parser(type3) {
-    return (input, init2) => text_default3(input, init2).then((text2) => new DOMParser().parseFromString(text2, type3));
+  // node_modules/d3-scale/src/number.js
+  function number2(x2) {
+    return +x2;
   }
-  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();
+  // node_modules/d3-scale/src/continuous.js
+  var unit = [0, 1];
+  function identity3(x2) {
+    return x2;
+  }
+  function normalize(a2, b2) {
+    return (b2 -= a2 = +a2) ? function(x2) {
+      return (x2 - a2) / b2;
+    } : constants(isNaN(b2) ? NaN : 0.5);
+  }
+  function clamper(a2, b2) {
+    var t2;
+    if (a2 > b2) t2 = a2, a2 = b2, b2 = t2;
+    return function(x2) {
+      return Math.max(a2, Math.min(b2, x2));
+    };
+  }
+  function bimap(domain, range3, interpolate) {
+    var d0 = domain[0], d1 = domain[1], r0 = range3[0], r1 = range3[1];
+    if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);
+    else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
+    return function(x2) {
+      return r0(d0(x2));
+    };
+  }
+  function polymap(domain, range3, interpolate) {
+    var j2 = Math.min(domain.length, range3.length) - 1, d2 = new Array(j2), r2 = new Array(j2), i3 = -1;
+    if (domain[j2] < domain[0]) {
+      domain = domain.slice().reverse();
+      range3 = range3.slice().reverse();
     }
+    while (++i3 < j2) {
+      d2[i3] = normalize(domain[i3], domain[i3 + 1]);
+      r2[i3] = interpolate(range3[i3], range3[i3 + 1]);
+    }
+    return function(x2) {
+      var i4 = bisect_default(domain, x2, 1, j2) - 1;
+      return r2[i4](d2[i4](x2));
+    };
   }
-  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 copy(source, target) {
+    return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
+  }
+  function transformer2() {
+    var domain = unit, range3 = unit, interpolate = value_default, transform2, untransform, unknown, clamp3 = identity3, piecewise, output, input;
+    function rescale() {
+      var n3 = Math.min(domain.length, range3.length);
+      if (clamp3 !== identity3) clamp3 = clamper(domain[0], domain[n3 - 1]);
+      piecewise = n3 > 2 ? polymap : bimap;
+      output = input = null;
+      return scale;
+    }
+    function scale(x2) {
+      return x2 == null || isNaN(x2 = +x2) ? unknown : (output || (output = piecewise(domain.map(transform2), range3, interpolate)))(transform2(clamp3(x2)));
+    }
+    scale.invert = function(y2) {
+      return clamp3(untransform((input || (input = piecewise(range3, domain.map(transform2), number_default)))(y2)));
+    };
+    scale.domain = function(_2) {
+      return arguments.length ? (domain = Array.from(_2, number2), rescale()) : domain.slice();
+    };
+    scale.range = function(_2) {
+      return arguments.length ? (range3 = Array.from(_2), rescale()) : range3.slice();
+    };
+    scale.rangeRound = function(_2) {
+      return range3 = Array.from(_2), interpolate = round_default, rescale();
+    };
+    scale.clamp = function(_2) {
+      return arguments.length ? (clamp3 = _2 ? true : identity3, rescale()) : clamp3 !== identity3;
+    };
+    scale.interpolate = function(_2) {
+      return arguments.length ? (interpolate = _2, rescale()) : interpolate;
+    };
+    scale.unknown = function(_2) {
+      return arguments.length ? (unknown = _2, scale) : unknown;
+    };
+    return function(t2, u2) {
+      transform2 = t2, untransform = u2;
+      return rescale();
+    };
+  }
+  function continuous() {
+    return transformer2()(identity3, identity3);
+  }
+
+  // node_modules/d3-format/src/formatDecimal.js
+  function formatDecimal_default(x2) {
+    return Math.abs(x2 = Math.round(x2)) >= 1e21 ? x2.toLocaleString("en").replace(/,/g, "") : x2.toString(10);
+  }
+  function formatDecimalParts(x2, p2) {
+    if ((i3 = (x2 = p2 ? x2.toExponential(p2 - 1) : x2.toExponential()).indexOf("e")) < 0) return null;
+    var i3, coefficient = x2.slice(0, i3);
+    return [
+      coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
+      +x2.slice(i3 + 1)
+    ];
+  }
+
+  // node_modules/d3-format/src/exponent.js
+  function exponent_default(x2) {
+    return x2 = formatDecimalParts(Math.abs(x2)), x2 ? x2[1] : NaN;
+  }
+
+  // node_modules/d3-format/src/formatGroup.js
+  function formatGroup_default(grouping, thousands) {
+    return function(value, width) {
+      var i3 = value.length, t2 = [], j2 = 0, g3 = grouping[0], length2 = 0;
+      while (i3 > 0 && g3 > 0) {
+        if (length2 + g3 + 1 > width) g3 = Math.max(1, width - length2);
+        t2.push(value.substring(i3 -= g3, i3 + g3));
+        if ((length2 += g3 + 1) > width) break;
+        g3 = grouping[j2 = (j2 + 1) % grouping.length];
       }
+      return t2.reverse().join(thousands);
+    };
+  }
+
+  // node_modules/d3-format/src/formatNumerals.js
+  function formatNumerals_default(numerals) {
+    return function(value) {
+      return value.replace(/[0-9]/g, function(i3) {
+        return numerals[+i3];
+      });
+    };
+  }
+
+  // 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]
     });
   }
-  function encodeIssueRtree(d) {
-    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
+  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 + "";
   }
-  function updateRtree(item, replace) {
-    _cache.rtree.remove(item, (a, b) => a.data.id === b.data.id);
-    if (replace) {
-      _cache.rtree.insert(item);
+  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(s2) {
+    out: for (var n3 = s2.length, i3 = 1, i0 = -1, i1; i3 < n3; ++i3) {
+      switch (s2[i3]) {
+        case ".":
+          i0 = i1 = i3;
+          break;
+        case "0":
+          if (i0 === 0) i0 = i3;
+          i1 = i3;
+          break;
+        default:
+          if (!+s2[i3]) break out;
+          if (i0 > 0) i0 = 0;
+          break;
+      }
     }
+    return i0 > 0 ? s2.slice(0, i0) + s2.slice(i1 + 1) : s2;
   }
-  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);
-      } else {
-        const compare = capture.toLowerCase();
-        if (_krData.localizeStrings[compare]) {
-          capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare]);
+
+  // node_modules/d3-format/src/formatPrefixAuto.js
+  var prefixExponent;
+  function formatPrefixAuto_default(x2, p2) {
+    var d2 = formatDecimalParts(x2, p2);
+    if (!d2) return x2 + "";
+    var coefficient = d2[0], exponent = d2[1], i3 = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n3 = coefficient.length;
+    return i3 === n3 ? coefficient : i3 > n3 ? coefficient + new Array(i3 - n3 + 1).join("0") : i3 > 0 ? coefficient.slice(0, i3) + "." + coefficient.slice(i3) : "0." + new Array(1 - i3).join("0") + formatDecimalParts(x2, Math.max(0, p2 + i3 - 1))[0];
+  }
+
+  // node_modules/d3-format/src/formatRounded.js
+  function formatRounded_default(x2, p2) {
+    var d2 = formatDecimalParts(x2, p2);
+    if (!d2) return x2 + "";
+    var coefficient = d2[0], exponent = d2[1];
+    return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1) : coefficient + new Array(exponent - coefficient.length + 2).join("0");
+  }
+
+  // node_modules/d3-format/src/formatTypes.js
+  var formatTypes_default = {
+    "%": (x2, p2) => (x2 * 100).toFixed(p2),
+    "b": (x2) => Math.round(x2).toString(2),
+    "c": (x2) => x2 + "",
+    "d": formatDecimal_default,
+    "e": (x2, p2) => x2.toExponential(p2),
+    "f": (x2, p2) => x2.toFixed(p2),
+    "g": (x2, p2) => x2.toPrecision(p2),
+    "o": (x2) => Math.round(x2).toString(8),
+    "p": (x2, p2) => formatRounded_default(x2 * 100, p2),
+    "r": formatRounded_default,
+    "s": formatPrefixAuto_default,
+    "X": (x2) => Math.round(x2).toString(16).toUpperCase(),
+    "x": (x2) => Math.round(x2).toString(16)
+  };
+
+  // node_modules/d3-format/src/identity.js
+  function identity_default4(x2) {
+    return x2;
+  }
+
+  // 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_default4 : 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_default4 : 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, precision3 = specifier.precision, trim = specifier.trim, type2 = specifier.type;
+      if (type2 === "n") comma = true, type2 = "g";
+      else if (!formatTypes_default[type2]) precision3 === void 0 && (precision3 = 12), trim = true, type2 = "g";
+      if (zero3 || fill === "0" && align === "=") zero3 = true, fill = "0", align = "=";
+      var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type2) ? "0" + type2.toLowerCase() : "", suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type2) ? percent : "";
+      var formatType = formatTypes_default[type2], maybeSuffix = /[defgprs%]/.test(type2);
+      precision3 = precision3 === void 0 ? 6 : /[gprs]/.test(type2) ? Math.max(1, Math.min(21, precision3)) : Math.max(0, Math.min(20, precision3));
+      function format2(value) {
+        var valuePrefix = prefix, valueSuffix = suffix, i3, n3, c2;
+        if (type2 === "c") {
+          valueSuffix = formatType(value) + valueSuffix;
+          value = "";
         } else {
-          capture = unescape_default(capture);
+          value = +value;
+          var valueNegative = value < 0 || 1 / value < 0;
+          value = isNaN(value) ? nan : formatType(Math.abs(value), precision3);
+          if (trim) value = formatTrim_default(value);
+          if (valueNegative && +value === 0 && sign2 !== "+") valueNegative = false;
+          valuePrefix = (valueNegative ? sign2 === "(" ? sign2 : minus : sign2 === "-" || sign2 === "(" ? "" : sign2) + valuePrefix;
+          valueSuffix = (type2 === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : "");
+          if (maybeSuffix) {
+            i3 = -1, n3 = value.length;
+            while (++i3 < n3) {
+              if (c2 = value.charCodeAt(i3), 48 > c2 || c2 > 57) {
+                valueSuffix = (c2 === 46 ? decimal + value.slice(i3 + 1) : value.slice(i3)) + valueSuffix;
+                value = value.slice(0, i3);
+                break;
+              }
+            }
+          }
+        }
+        if (comma && !zero3) value = group(value, Infinity);
+        var length2 = valuePrefix.length + value.length + valueSuffix.length, padding = length2 < width ? new Array(width - length2 + 1).join(fill) : "";
+        if (comma && zero3) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
+        switch (align) {
+          case "<":
+            value = valuePrefix + value + valueSuffix + padding;
+            break;
+          case "=":
+            value = valuePrefix + padding + value + valueSuffix;
+            break;
+          case "^":
+            value = padding.slice(0, length2 = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length2);
+            break;
+          default:
+            value = padding + valuePrefix + value + valueSuffix;
+            break;
         }
+        return numerals(value);
       }
-      replacements["var" + i2] = capture;
+      format2.toString = function() {
+        return specifier + "";
+      };
+      return format2;
     }
-    return replacements;
-  }
-  function parseError(capture, idType) {
-    const compare = capture.toLowerCase();
-    if (_krData.localizeStrings[compare]) {
-      capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare]);
+    function formatPrefix2(specifier, value) {
+      var f2 = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)), e3 = Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3, k2 = Math.pow(10, -e3), prefix = prefixes[8 + e3 / 3];
+      return function(value2) {
+        return f2(k2 * value2) + prefix;
+      };
     }
-    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);
+    return {
+      format: newFormat,
+      formatPrefix: formatPrefix2
+    };
+  }
+
+  // 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), precision3;
+    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(precision3 = precisionPrefix_default(step, value))) specifier.precision = precision3;
+        return formatPrefix(specifier, value);
+      }
+      case "":
+      case "e":
+      case "g":
+      case "p":
+      case "r": {
+        if (specifier.precision == null && !isNaN(precision3 = precisionRound_default(step, Math.max(Math.abs(start2), Math.abs(stop))))) specifier.precision = precision3 - (specifier.type === "e");
         break;
-      case "370":
-        capture = parse370(capture);
+      }
+      case "f":
+      case "%": {
+        if (specifier.precision == null && !isNaN(precision3 = precisionFixed_default(step))) specifier.precision = precision3 - (specifier.type === "%") * 2;
         break;
+      }
     }
-    return capture;
-    function linkErrorObject2(d) {
-      return { html: `<a class="error_object_link">${d}</a>` };
+    return format(specifier);
+  }
+
+  // node_modules/d3-scale/src/linear.js
+  function linearish(scale) {
+    var domain = scale.domain;
+    scale.ticks = function(count) {
+      var d2 = domain();
+      return ticks(d2[0], d2[d2.length - 1], count == null ? 10 : count);
+    };
+    scale.tickFormat = function(count, specifier) {
+      var d2 = domain();
+      return tickFormat(d2[0], d2[d2.length - 1], count == null ? 10 : count, specifier);
+    };
+    scale.nice = function(count) {
+      if (count == null) count = 10;
+      var d2 = domain();
+      var i0 = 0;
+      var i1 = d2.length - 1;
+      var start2 = d2[i0];
+      var stop = d2[i1];
+      var prestep;
+      var step;
+      var maxIter = 10;
+      if (stop < start2) {
+        step = start2, start2 = stop, stop = step;
+        step = i0, i0 = i1, i1 = step;
+      }
+      while (maxIter-- > 0) {
+        step = tickIncrement(start2, stop, count);
+        if (step === prestep) {
+          d2[i0] = start2;
+          d2[i1] = stop;
+          return domain(d2);
+        } 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;
+        }
+        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, n3 = 1, domain = [0.5], range3 = [0, 1], unknown;
+    function scale(x2) {
+      return x2 != null && x2 <= x2 ? range3[bisect_default(domain, x2, 0, n3)] : unknown;
     }
-    function linkEntity2(d) {
-      return { html: `<a class="error_entity_link">${d}</a>` };
+    function rescale() {
+      var i3 = -1;
+      domain = new Array(n3);
+      while (++i3 < n3) domain[i3] = ((i3 + 1) * x12 - (i3 - n3) * x05) / (n3 + 1);
+      return scale;
     }
-    function linkURL(d) {
-      return { html: `<a class="kr_external_link" target="_blank" href="${d}">${d}</a>` };
+    scale.domain = function(_2) {
+      return arguments.length ? ([x05, x12] = _2, x05 = +x05, x12 = +x12, rescale()) : [x05, x12];
+    };
+    scale.range = function(_2) {
+      return arguments.length ? (n3 = (range3 = Array.from(_2)).length - 1, rescale()) : range3.slice();
+    };
+    scale.invertExtent = function(y2) {
+      var i3 = range3.indexOf(y2);
+      return i3 < 0 ? [NaN, NaN] : i3 < 1 ? [x05, domain[0]] : i3 >= n3 ? [domain[n3 - 1], x12] : [domain[i3 - 1], domain[i3]];
+    };
+    scale.unknown = function(_2) {
+      return arguments.length ? (unknown = _2, scale) : scale;
+    };
+    scale.thresholds = function() {
+      return domain.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(a2, b2, steps2, units) {
+      a2 = Number(a2);
+      b2 = Number(b2);
+      var sample = quantize().domain([0, 1]).range(quantize_default(number_default(a2, b2), steps2));
+      return function(t2) {
+        return String(sample(t2)) + (units || "");
+      };
     }
-    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 reset(selection2) {
+      selection2.style("stroke-opacity", null).style("stroke-width", null).style("fill-opacity", null).style("r", null);
     }
-    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 setAnimationParams(transition2, fromTo) {
+      var toFrom = fromTo === "from" ? "to" : "from";
+      transition2.styleTween("stroke-opacity", function(d2) {
+        return ratchetyInterpolator(
+          _params[d2.id][toFrom].opacity,
+          _params[d2.id][fromTo].opacity,
+          steps
+        );
+      }).styleTween("stroke-width", function(d2) {
+        return ratchetyInterpolator(
+          _params[d2.id][toFrom].width,
+          _params[d2.id][fromTo].width,
+          steps,
+          "px"
+        );
+      }).styleTween("fill-opacity", function(d2) {
+        return ratchetyInterpolator(
+          _params[d2.id][toFrom].opacity,
+          _params[d2.id][fromTo].opacity,
+          steps
+        );
+      }).styleTween("r", function(d2) {
+        return ratchetyInterpolator(
+          _params[d2.id][toFrom].width,
+          _params[d2.id][fromTo].width,
+          steps,
+          "px"
+        );
       });
-      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}`);
+    function calcAnimationParams(selection2) {
+      selection2.call(reset).each(function(d2) {
+        var s2 = select_default2(this);
+        var tag2 = s2.node().tagName;
+        var p2 = { "from": {}, "to": {} };
+        var opacity;
+        var width;
+        if (tag2 === "circle") {
+          opacity = Number(s2.style("fill-opacity") || 0.5);
+          width = Number(s2.style("r") || 15.5);
+        } else {
+          opacity = Number(s2.style("stroke-opacity") || 0.7);
+          width = Number(s2.style("stroke-width") || 10);
+        }
+        p2.tag = tag2;
+        p2.from.opacity = opacity * 0.6;
+        p2.to.opacity = opacity * 1.25;
+        p2.from.width = width * 0.7;
+        p2.to.width = width * (tag2 === "circle" ? 1.5 : 1);
+        _params[d2.id] = p2;
       });
-      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] });
+    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;
       }
-      return "";
-    }
-    function parse20(capture2) {
-      let newList = [];
-      const items = capture2.split(",");
-      items.forEach((item) => {
-        const id2 = linkEntity2("n" + item.slice(1));
-        newList.push(id2);
+      if (!(0, import_fast_deep_equal2.default)(currSelected.data(), _selected.data()) || currClassed !== _classed) {
+        _selected.call(reset);
+        _classed = currClassed;
+        _selected = currSelected.call(calcAnimationParams);
+      }
+      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 newList.join(", ");
     }
-  }
-  var keepRight_default = {
-    title: "keepRight",
-    init() {
-      _mainFileFetcher.get("keepRight").then((d) => _krData = d);
-      if (!_cache) {
-        this.reset();
+    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();
+        }
       }
-      this.event = utilRebind(this, dispatch2, "on");
-    },
-    reset() {
-      if (_cache) {
-        Object.values(_cache.inflightTile).forEach(abortRequest);
+    };
+    behavior.off = function() {
+      _done = true;
+      if (_timer) {
+        _timer.stop();
       }
-      _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));
-          });
-          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);
-      }
-      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 {
-          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();
-    }
-  };
-
-  // 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();
-      }
-    });
+      _selected.interrupt().call(reset);
+    };
+    return behavior;
   }
-  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];
+
+  // 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 {
+        context.ui().flash.duration(2e3).iconName("#iD-operation-" + _operation.id).iconClass("operation").label(_operation.annotation() || _operation.title)();
+        if (_operation.point) _operation.point(null);
+        _operation();
       }
-    });
-  }
-  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 relativeBearing(p1, p2) {
-    let angle2 = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
-    if (angle2 < 0) {
-      angle2 += 2 * Math.PI;
+    function behavior() {
+      if (_operation && _operation.available()) {
+        context.keybinding().on(_operation.keys, keypress);
+      }
+      return behavior;
     }
-    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"
+    behavior.off = function() {
+      context.keybinding().off(_operation.keys);
     };
-    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;
+    behavior.which = function(_2) {
+      if (!arguments.length) return _operation;
+      _operation = _2;
+      return behavior;
+    };
+    return behavior;
   }
-  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);
+
+  // 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(n3) {
+      return n3.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()));
       }
-      _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;
-            }
-          });
+      return actionCircularize(entityID, context.projection);
+    }
+    var operation2 = function() {
+      if (!_actions.length) return;
+      var combinedAction = function(graph, t2) {
+        _actions.forEach(function(action) {
+          if (!action.disabled(graph)) {
+            graph = action(graph, t2);
+          }
         });
-        _cache2.inflightTile[tile.id] = requests;
-      });
-    },
-    getComments(item) {
-      if (item.comments) {
-        return Promise.resolve(item);
-      }
-      const key = item.issueKey;
-      let qParams = {};
-      if (key === "ow") {
-        qParams = item.identifier;
-      } else if (key === "mr") {
-        qParams.tileX = item.identifier.x;
-        qParams.tileY = item.identifier.y;
-      } else if (key === "tr") {
-        qParams.targetId = item.identifier;
-      }
-      const url = `${_impOsmUrls[key]}/retrieveComments?` + utilQsString(qParams);
-      const cacheComments = (data) => {
-        item.comments = data.comments ? data.comments.reverse() : [];
-        this.replaceItem(item);
+        return graph;
       };
-      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);
-      }
-      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";
-        }
-        if (d.newComment) {
-          payload.text = d.newComment;
+      combinedAction.transitionable = true;
+      context.perform(combinedAction, operation2.annotation());
+      window.setTimeout(function() {
+        context.validator().validate();
+      }, 300);
+    };
+    operation2.available = function() {
+      return _actions.length && selectedIDs.length === _actions.length;
+    };
+    operation2.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";
         }
-        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
+        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);
             });
-            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;
-            }
+            return true;
           }
-          if (callback)
-            callback(null, d);
-        }).catch((err2) => {
-          delete _cache2.inflightPost[d.id];
-          if (callback)
-            callback(err2.message);
-        });
+        }
+        return false;
       }
-    },
-    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;
-    }
-  };
-
-  // 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
     };
-  }
-  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);
-      }
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
+      return disable ? _t.append("operations.circularize." + disable + "." + _amount) : _t.append("operations.circularize.description." + _amount);
     };
-    return obj;
+    operation2.annotation = function() {
+      return _t("operations.circularize.annotation.feature", { n: _actions.length });
+    };
+    operation2.id = "circularize";
+    operation2.keys = [_t("operations.circularize.key")];
+    operation2.title = _t.append("operations.circularize.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
-  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;
-      }
-    }
-    if (base && !originIndependentUrl.test(href)) {
-      href = resolveUrl(base, href);
+
+  // modules/ui/cmd.js
+  var uiCmd = function(code) {
+    var detected = utilDetect();
+    if (detected.os === "mac") {
+      return code;
     }
-    try {
-      href = encodeURI(href).replace(/%25/g, "%");
-    } catch (e) {
-      return null;
+    if (detected.os === "win") {
+      if (code === "\u2318\u21E7Z") return "Ctrl+Y";
     }
-    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 + "/";
+    var result = "", replacements = {
+      "\u2318": "Ctrl",
+      "\u21E7": "Shift",
+      "\u2325": "Alt",
+      "\u232B": "Backspace",
+      "\u2326": "Delete"
+    };
+    for (var i3 = 0; i3 < code.length; i3++) {
+      if (code[i3] in replacements) {
+        result += replacements[code[i3]] + (i3 < code.length - 1 ? "+" : "");
       } else {
-        baseUrls[" " + base] = rtrim(base, "/", 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;
+        result += code[i3];
       }
-      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];
+    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(n3) {
+      return n3.loc;
+    });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation2 = 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 i3 = nodes2.indexOf(id2);
+          if (i3 === 0) {
+            i3++;
+          } else if (i3 === nodes2.length - 1) {
+            i3--;
+          } else {
+            var a2 = geoSphericalDistance(entity.loc, context.entity(nodes2[i3 - 1]).loc);
+            var b2 = geoSphericalDistance(entity.loc, context.entity(nodes2[i3 + 1]).loc);
+            i3 = a2 < b2 ? i3 - 1 : i3 + 1;
+          }
+          nextSelectedID = nodes2[i3];
+          nextSelectedLoc = context.entity(nextSelectedID).loc;
         }
       }
-    }
-    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 "|";
+      context.perform(action, operation2.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 {
-        return " |";
+        context.enter(modeBrowse(context));
       }
-    }), 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 "";
-    }
-    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;
+    };
+    operation2.available = function() {
+      return true;
+    };
+    operation2.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 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;
+      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;
       }
-    }
-    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;
+      function hasWikidataTag(id2) {
+        var entity = context.entity(id2);
+        return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
       }
-      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;
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
       }
-      const [indentInNode] = matchIndentInNode;
-      if (indentInNode.length >= indentToCode.length) {
-        return node.slice(indentToCode.length);
+      function protectedMember(id2) {
+        var entity = context.entity(id2);
+        if (entity.type !== "way") return false;
+        var parents = context.graph().parentRelations(entity);
+        for (var i3 = 0; i3 < parents.length; i3++) {
+          var parent = parents[i3];
+          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;
       }
-      return node;
-    }).join("\n");
+    };
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
+      return disable ? _t.append("operations.delete." + disable + "." + multi) : _t.append("operations.delete.description." + multi);
+    };
+    operation2.annotation = function() {
+      return selectedIDs.length === 1 ? _t("operations.delete.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.delete.annotation.feature", { n: selectedIDs.length });
+    };
+    operation2.id = "delete";
+    operation2.keys = [uiCmd("\u2318\u232B"), uiCmd("\u2318\u2326"), uiCmd("\u2326")];
+    operation2.title = _t.append("operations.delete.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
-  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]
-        };
-      }
-    }
-    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() : cap[2],
-          text: text2
-        };
+
+  // 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(n3) {
+      return n3.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()));
       }
-    }
-    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();
+      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 {
-          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, "");
-        return {
-          type: "blockquote",
-          raw: cap[0],
-          tokens: this.lexer.blockTokens(text2, []),
-          text: text2
-        };
       }
+      return null;
     }
-    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]\] +/, "");
-            }
+    var operation2 = function() {
+      if (!_actions.length) return;
+      var combinedAction = function(graph, t2) {
+        _actions.forEach(function(action) {
+          if (!action.disabled(graph)) {
+            graph = action(graph, t2);
           }
-          list.items.push({
-            type: "list_item",
-            raw,
-            task: !!istask,
-            checked: ischecked,
-            loose: false,
-            text: itemContents
-          });
-          list.raw += raw;
+        });
+        return graph;
+      };
+      combinedAction.transitionable = true;
+      context.perform(combinedAction, operation2.annotation());
+      window.setTimeout(function() {
+        context.validator().validate();
+      }, 300);
+    };
+    operation2.available = function() {
+      return _actions.length && selectedIDs.length === _actions.length;
+    };
+    operation2.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";
         }
-        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;
+        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 (!list.loose && spacers.length && hasMultipleLineBreaks) {
-            list.loose = true;
-            list.items[i2].loose = true;
+          if (missing.length) {
+            missing.forEach(function(loc) {
+              context.loadTileAtLoc(loc);
+            });
+            return true;
           }
         }
-        return list;
+        return false;
       }
-    }
-    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);
+    };
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
+      return disable ? _t.append("operations.orthogonalize." + disable + "." + _amount) : _t.append("operations.orthogonalize.description." + _type + "." + _amount);
+    };
+    operation2.annotation = function() {
+      return _t("operations.orthogonalize.annotation." + _type, { n: _actions.length });
+    };
+    operation2.id = "orthogonalize";
+    operation2.keys = [_t("operations.orthogonalize.key")];
+    operation2.title = _t.append("operations.orthogonalize.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
+  }
+
+  // modules/operations/reflect.js
+  function operationReflectShort(context, selectedIDs) {
+    return operationReflect(context, selectedIDs, "short");
+  }
+  function operationReflectLong(context, selectedIDs) {
+    return operationReflect(context, selectedIDs, "long");
+  }
+  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(n3) {
+      return n3.loc;
+    });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation2 = function() {
+      var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === "long"));
+      context.perform(action, operation2.annotation());
+      window.setTimeout(function() {
+        context.validator().validate();
+      }, 300);
+    };
+    operation2.available = function() {
+      return nodes.length >= 3;
+    };
+    operation2.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 token;
+        return false;
       }
-    }
-    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]
-        };
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
       }
-    }
-    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 };
+    };
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
+      return disable ? _t.append("operations.reflect." + disable + "." + multi) : _t.append("operations.reflect.description." + axis + "." + multi);
+    };
+    operation2.annotation = function() {
+      return _t("operations.reflect.annotation." + axis + ".feature", { n: selectedIDs.length });
+    };
+    operation2.id = "reflect-" + axis;
+    operation2.keys = [_t("operations.reflect.key." + axis)];
+    operation2.title = _t.append("operations.reflect.title." + axis);
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
+  }
+
+  // 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(n3) {
+      return n3.loc;
+    });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation2 = function() {
+      context.enter(modeMove(context, selectedIDs));
+    };
+    operation2.available = function() {
+      return selectedIDs.length > 0;
+    };
+    operation2.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;
           }
-          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;
         }
+        return false;
       }
-    }
-    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])
-        };
-      }
-    }
-    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)
-        };
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
       }
-    }
-    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])
-        };
+    };
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
+      return disable ? _t.append("operations.move." + disable + "." + multi) : _t.append("operations.move.description." + multi);
+    };
+    operation2.annotation = function() {
+      return selectedIDs.length === 1 ? _t("operations.move.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.move.annotation.feature", { n: selectedIDs.length });
+    };
+    operation2.id = "move";
+    operation2.keys = [_t("operations.move.key")];
+    operation2.title = _t.append("operations.move.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    operation2.mouseOnly = true;
+    return operation2;
+  }
+
+  // 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;
       }
-    }
-    escape(src) {
-      const cap = this.rules.inline.escape.exec(src);
-      if (cap) {
-        return {
-          type: "escape",
-          raw: cap[0],
-          text: escape4(cap[1])
-        };
+      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(n3) {
+          return projection2(n3.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();
     }
-    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;
+    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 {
-          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]
-        };
       }
+      return _pivot2;
     }
-    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];
-          }
-        } 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);
-          }
-        }
-        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);
-      }
+    function finish(d3_event) {
+      d3_event.stopPropagation();
+      context.replace(actionNoop(), annotation);
+      context.enter(modeSelect(context, entityIDs));
     }
-    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);
-      }
+    function cancel() {
+      if (_prevGraph) context.pop();
+      context.enter(modeSelect(context, entityIDs));
     }
-    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)
-            };
+    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;
+  }
+
+  // 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(n3) {
+      return n3.loc;
+    });
+    var extent = utilTotalExtent(selectedIDs, context.graph());
+    var operation2 = function() {
+      context.enter(modeRotate(context, selectedIDs));
+    };
+    operation2.available = function() {
+      return nodes.length >= 2;
+    };
+    operation2.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;
           }
-          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)
-          };
         }
+        return false;
       }
-    }
-    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
-        };
+      function incompleteRelation(id2) {
+        var entity = context.entity(id2);
+        return entity.type === "relation" && !entity.isComplete(context.graph());
       }
-    }
-    br(src) {
-      const cap = this.rules.inline.br.exec(src);
-      if (cap) {
-        return {
-          type: "br",
-          raw: cap[0]
-        };
+    };
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
+      return disable ? _t.append("operations.rotate." + disable + "." + multi) : _t.append("operations.rotate.description." + multi);
+    };
+    operation2.annotation = function() {
+      return selectedIDs.length === 1 ? _t("operations.rotate.annotation." + context.graph().geometry(selectedIDs[0])) : _t("operations.rotate.annotation.feature", { n: selectedIDs.length });
+    };
+    operation2.id = "rotate";
+    operation2.keys = [_t("operations.rotate.key")];
+    operation2.title = _t.append("operations.rotate.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    operation2.mouseOnly = true;
+    return operation2;
+  }
+
+  // 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 _cache5;
+    var _origin;
+    var _nudgeInterval;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function doMove(nudge) {
+      nudge = nudge || [0, 0];
+      var fn;
+      if (_prevGraph !== context.graph()) {
+        _cache5 = {};
+        _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, _cache5));
+      _prevGraph = context.graph();
     }
-    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 startNudge(nudge) {
+      if (_nudgeInterval) window.clearInterval(_nudgeInterval);
+      _nudgeInterval = window.setInterval(function() {
+        context.map().pan(nudge);
+        doMove(nudge);
+      }, 50);
     }
-    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;
-        }
-        return {
-          type: "link",
-          raw: cap[0],
-          text: text2,
-          href,
-          tokens: [
-            {
-              type: "text",
-              raw: text2,
-              text: text2
-            }
-          ]
-        };
+    function stopNudge() {
+      if (_nudgeInterval) {
+        window.clearInterval(_nudgeInterval);
+        _nudgeInterval = null;
       }
     }
-    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;
-          }
-        }
-        return {
-          type: "link",
-          raw: cap[0],
-          text: text2,
-          href,
-          tokens: [
-            {
-              type: "text",
-              raw: text2,
-              text: text2
-            }
-          ]
-        };
+    function move() {
+      doMove();
+      var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
+      if (nudge) {
+        startNudge(nudge);
+      } else {
+        stopNudge();
       }
     }
-    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
-        };
+    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));
       }
+      stopNudge();
     }
-  };
-  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*])/
-    },
-    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
-    },
-    em: {
-      start: /^_|\*/,
-      middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
-      endAst: /\*(?!\*)/g,
-      endUnd: /_(?!_)/g
-    },
-    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 undone() {
+      context.enter(modeBrowse(context));
+    }
+    mode.enter = function() {
+      _origin = context.map().mouseCoordinates();
+      _prevGraph = null;
+      _cache5 = {};
+      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);
+    };
+    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;
   }
-  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);
+
+  // 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);
+        }
       }
-      out += "&#" + ch + ";";
+      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 out;
+    function behavior() {
+      context.keybinding().on(uiCmd("\u2318V"), doPaste);
+      return behavior;
+    }
+    behavior.off = function() {
+      context.keybinding().off(uiCmd("\u2318V"));
+    };
+    return behavior;
   }
-  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
+
+  // modules/behavior/drag.js
+  function behaviorDrag() {
+    var dispatch14 = 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);
       };
-      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;
+    };
+    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];
+      }
+      d3_event.stopPropagation();
+      function pointermove(d3_event2) {
+        if (_pointerId !== (d3_event2.pointerId || "mouse")) return;
+        var p2 = pointerLocGetter(d3_event2);
+        if (!started) {
+          var dist = geoVecLength(startOrigin, p2);
+          var tolerance = d3_event2.pointerType === "pen" ? _penTolerancePx : _tolerancePx;
+          if (dist < tolerance) return;
+          started = true;
+          dispatch14.call("start", this, d3_event2, _targetEntity);
         } else {
-          rules.inline = inline.gfm;
+          startOrigin = p2;
+          d3_event2.stopPropagation();
+          d3_event2.preventDefault();
+          var dx = p2[0] - startOrigin[0];
+          var dy = p2[1] - startOrigin[1];
+          dispatch14.call("move", this, d3_event2, _targetEntity, [p2[0] + offset[0], p2[1] + offset[1]], [dx, dy]);
         }
       }
-      this.tokenizer.rules = rules;
-    }
-    static get rules() {
-      return {
-        block,
-        inline
-      };
-    }
-    static lex(src, options2) {
-      const lexer2 = new Lexer(options2);
-      return lexer2.lex(src);
-    }
-    static lexInline(src, options2) {
-      const lexer2 = new Lexer(options2);
-      return lexer2.inlineTokens(src);
-    }
-    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);
+      function pointerup(d3_event2) {
+        if (_pointerId !== (d3_event2.pointerId || "mouse")) return;
+        _pointerId = null;
+        if (started) {
+          dispatch14.call("end", this, d3_event2, _targetEntity);
+          d3_event2.preventDefault();
+        }
+        select_default2(window).on(_pointerPrefix + "move.drag", null).on(_pointerPrefix + "up.drag pointercancel.drag", null);
+        selectEnable();
       }
-      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);
-        });
-      }
-      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);
+    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);
+            }
           }
-          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);
-            }
-          });
-          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);
+        };
+      }
+      selection2.on(_pointerPrefix + "down.drag" + _selector, delegate);
+    }
+    behavior.off = function(selection2) {
+      selection2.on(_pointerPrefix + "down.drag" + _selector, null);
+    };
+    behavior.selector = function(_2) {
+      if (!arguments.length) return _selector;
+      _selector = _2;
+      return behavior;
+    };
+    behavior.origin = function(_2) {
+      if (!arguments.length) return _origin;
+      _origin = _2;
+      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(_2) {
+      if (!arguments.length) return _targetNode;
+      _targetNode = _2;
+      return behavior;
+    };
+    behavior.targetEntity = function(_2) {
+      if (!arguments.length) return _targetEntity;
+      _targetEntity = _2;
+      return behavior;
+    };
+    behavior.surface = function(_2) {
+      if (!arguments.length) return _surface;
+      _surface = _2;
+      return behavior;
+    };
+    return utilRebind(behavior, dispatch14, "on");
+  }
+
+  // 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);
+    }
+    function stopNudge() {
+      if (_nudgeInterval) {
+        window.clearInterval(_nudgeInterval);
+        _nudgeInterval = 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");
           }
-          continue;
+          return _t("operations.connect.annotation.from_vertex.to_sibling_vertex");
         }
-        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 _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);
+    }
+    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);
       }
-      this.state.top = true;
-      return tokens;
     }
-    inline(src, tokens = []) {
-      this.inlineQueue.push({ src, tokens });
-      return tokens;
+    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);
+      }
     }
-    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);
-            }
-          }
+    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();
       }
-      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);
+      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());
       }
-      while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
-        maskedSrc = maskedSrc.slice(0, match.index) + "++" + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
+      _activeEntity = entity;
+      _startLoc = entity.loc;
+      hover.ignoreVertex(entity.geometry(context.graph()) === "vertex");
+      context.surface().selectAll("." + _activeEntity.id).classed("active", true);
+      context.enter(mode);
+    }
+    function datum2(d3_event) {
+      if (!d3_event || d3_event.altKey) {
+        return {};
+      } else {
+        var d2 = d3_event.target.__data__;
+        return d2 && d2.properties && d2.properties.target ? d2 : {};
       }
-      while (src) {
-        if (!keepPrevChar) {
-          prevChar = "";
-        }
-        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;
-        }
-        if (token = this.tokenizer.escape(src)) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
-        }
-        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);
+    }
+    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 d2 = datum2(d3_event);
+        target = d2 && d2.properties && d2.properties.entity;
+        var targetLoc = target && target.loc;
+        var targetNodes = d2 && d2.properties && d2.properties.nodes;
+        if (targetLoc) {
+          if (shouldSnapToNode(target)) {
+            loc = targetLoc;
           }
-          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);
+        } else if (targetNodes) {
+          edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
+          if (edge) {
+            loc = edge.loc;
           }
-          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;
+      }
+      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());
+      }
+      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() }
+          ))();
         }
-        if (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) {
-          src = src.substring(token.raw.length);
-          tokens.push(token);
-          continue;
+      } 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("")();
         }
-        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);
+      }
+      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;
+    }
+    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);
+    }
+    function hasInvalidGeometry(entity, graph) {
+      var parents = graph.parentWays(entity);
+      var i3, j2, k2;
+      for (i3 = 0; i3 < parents.length; i3++) {
+        var parent = parents[i3];
+        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 (k2 = 0; k2 < rings.length; k2++) {
+            nodes = rings[k2].nodes;
+            if (nodes.find(function(n3) {
+              return n3.id === entity.id;
+            })) {
+              activeIndex = k2;
+              if (geoHasSelfIntersections(nodes, entity.id)) {
+                return "multipolygonMember";
+              }
             }
-          });
-          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);
+            rings[k2].coords = nodes.map(function(n3) {
+              return n3.loc;
+            });
           }
-          keepPrevChar = true;
-          lastToken = tokens[tokens.length - 1];
-          if (lastToken && lastToken.type === "text") {
-            lastToken.raw += token.raw;
-            lastToken.text += token.text;
-          } else {
-            tokens.push(token);
+          for (k2 = 0; k2 < rings.length; k2++) {
+            if (k2 === activeIndex) continue;
+            if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k2].nodes, entity.id)) {
+              return "multipolygonRing";
+            }
           }
-          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 (activeIndex === null) {
+          nodes = parent.nodes.map(function(nodeID) {
+            return graph.entity(nodeID);
+          });
+          if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
+            return parent.geometry(graph);
           }
         }
       }
-      return tokens;
-    }
-  };
-  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;
-        }
-      }
-      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, true) + '">' + (escaped ? code : escape4(code, true)) + "</code></pre>\n";
-    }
-    blockquote(quote2) {
-      return `<blockquote>
-${quote2}</blockquote>
-`;
-    }
-    html(html2) {
-      return html2;
+      return false;
     }
-    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}>
-`;
+    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);
+      } else {
+        stopNudge();
       }
-      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>
-`;
     }
-    table(header, body) {
-      if (body)
-        body = `<tbody>${body}</tbody>`;
-      return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
-    }
-    tablerow(content) {
-      return `<tr>
-${content}</tr>
-`;
-    }
-    tablecell(content, flags) {
-      const type3 = flags.header ? "th" : "td";
-      const tag = flags.align ? `<${type3} align="${flags.align}">` : `<${type3}>`;
-      return tag + content + `</${type3}>
-`;
-    }
-    strong(text2) {
-      return `<strong>${text2}</strong>`;
-    }
-    em(text2) {
-      return `<em>${text2}</em>`;
-    }
-    codespan(text2) {
-      return `<code>${text2}</code>`;
-    }
-    br() {
-      return this.options.xhtml ? "<br/>" : "<br>";
-    }
-    del(text2) {
-      return `<del>${text2}</del>`;
-    }
-    link(href, title, text2) {
-      href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
-      if (href === null) {
-        return text2;
+    function end(d3_event, entity) {
+      if (_isCancelled) return;
+      var wasPoint = entity.geometry(context.graph()) === "point";
+      var d2 = datum2(d3_event);
+      var nope = d2 && d2.properties && d2.properties.nope || context.surface().classed("nope");
+      var target = d2 && d2.properties && d2.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)
+        );
       }
-      let out = '<a href="' + escape4(href) + '"';
-      if (title) {
-        out += ' title="' + title + '"';
+      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));
+        }
       }
-      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;
+    function _actionBounceBack(nodeID, toLoc) {
+      var moveNode = actionMoveNode(nodeID, toLoc);
+      var action = function(graph, t2) {
+        if (t2 === 1) context.pop();
+        return moveNode(graph, t2);
+      };
+      action.transitionable = true;
+      return action;
     }
-    text(text2) {
-      return text2;
-    }
-  };
-  var TextRenderer = class {
-    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 = {};
-    }
-    serialize(value) {
-      return value.toLowerCase().trim().replace(/<[!\/a-z].*?>/ig, "").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, "").replace(/\s/g, "-");
+    function cancel() {
+      drag.cancel();
+      context.enter(modeBrowse(context));
     }
-    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 (!isDryRun) {
-        this.seen[originalSlug] = occurenceAccumulator;
-        this.seen[slug] = 0;
+    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(_2) {
+      if (!arguments.length) return _restoreSelectedIDs;
+      _restoreSelectedIDs = _2;
+      return mode;
+    };
+    mode.behavior = drag;
+    return mode;
+  }
+
+  // node_modules/quickselect/index.js
+  function quickselect2(arr, k2, left, right, compare2) {
+    quickselectStep(arr, k2, left || 0, right || arr.length - 1, compare2 || defaultCompare);
+  }
+  function quickselectStep(arr, k2, left, right, compare2) {
+    while (right > left) {
+      if (right - left > 600) {
+        var n3 = right - left + 1;
+        var m2 = k2 - left + 1;
+        var z2 = Math.log(n3);
+        var s2 = 0.5 * Math.exp(2 * z2 / 3);
+        var sd = 0.5 * Math.sqrt(z2 * s2 * (n3 - s2) / n3) * (m2 - n3 / 2 < 0 ? -1 : 1);
+        var newLeft = Math.max(left, Math.floor(k2 - m2 * s2 / n3 + sd));
+        var newRight = Math.min(right, Math.floor(k2 + (n3 - m2) * s2 / n3 + sd));
+        quickselectStep(arr, k2, newLeft, newRight, compare2);
+      }
+      var t2 = arr[k2];
+      var i3 = left;
+      var j2 = right;
+      swap2(arr, left, k2);
+      if (compare2(arr[right], t2) > 0) swap2(arr, left, right);
+      while (i3 < j2) {
+        swap2(arr, i3, j2);
+        i3++;
+        j2--;
+        while (compare2(arr[i3], t2) < 0) i3++;
+        while (compare2(arr[j2], t2) > 0) j2--;
+      }
+      if (compare2(arr[left], t2) === 0) swap2(arr, left, j2);
+      else {
+        j2++;
+        swap2(arr, j2, right);
       }
-      return slug;
-    }
-    slug(value, options2 = {}) {
-      const slug = this.serialize(value);
-      return this.getNextSafeSlug(slug, options2.dryrun);
-    }
-  };
-  var Parser = 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();
+      if (j2 <= k2) left = j2 + 1;
+      if (k2 <= j2) right = j2 - 1;
     }
-    static parse(tokens, options2) {
-      const parser3 = new Parser(options2);
-      return parser3.parse(tokens);
+  }
+  function swap2(arr, i3, j2) {
+    var tmp = arr[i3];
+    arr[i3] = arr[j2];
+    arr[j2] = tmp;
+  }
+  function defaultCompare(a2, b2) {
+    return a2 < b2 ? -1 : a2 > b2 ? 1 : 0;
+  }
+
+  // node_modules/rbush/index.js
+  var RBush = class {
+    constructor(maxEntries = 9) {
+      this._maxEntries = Math.max(4, maxEntries);
+      this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
+      this.clear();
     }
-    static parseInline(tokens, options2) {
-      const parser3 = new Parser(options2);
-      return parser3.parseInline(tokens);
+    all() {
+      return this._all(this.data, []);
     }
-    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;
-          }
-        }
-        switch (token.type) {
-          case "space": {
-            continue;
-          }
-          case "hr": {
-            out += this.renderer.hr();
-            continue;
-          }
-          case "heading": {
-            out += this.renderer.heading(
-              this.parseInline(token.tokens),
-              token.depth,
-              unescape3(this.parseInline(token.tokens, this.textRenderer)),
-              this.slugger
-            );
-            continue;
-          }
-          case "code": {
-            out += this.renderer.code(
-              token.text,
-              token.lang,
-              token.escaped
-            );
-            continue;
-          }
-          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;
-          }
-          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);
-            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);
-            }
+    search(bbox2) {
+      let node = this.data;
+      const result = [];
+      if (!intersects(bbox2, node)) return result;
+      const toBBox = this.toBBox;
+      const nodesToSearch = [];
+      while (node) {
+        for (let i3 = 0; i3 < node.children.length; i3++) {
+          const child = node.children[i3];
+          const childBBox = node.leaf ? toBBox(child) : child;
+          if (intersects(bbox2, childBBox)) {
+            if (node.leaf) result.push(child);
+            else if (contains(bbox2, childBBox)) this._all(child, result);
+            else nodesToSearch.push(child);
           }
         }
+        node = nodesToSearch.pop();
       }
-      return out;
+      return result;
     }
-    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;
-          }
-        }
-        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);
-            }
+    collides(bbox2) {
+      let node = this.data;
+      if (!intersects(bbox2, node)) return false;
+      const nodesToSearch = [];
+      while (node) {
+        for (let i3 = 0; i3 < node.children.length; i3++) {
+          const child = node.children[i3];
+          const childBBox = node.leaf ? this.toBBox(child) : child;
+          if (intersects(bbox2, childBBox)) {
+            if (node.leaf || contains(bbox2, childBBox)) return true;
+            nodesToSearch.push(child);
           }
         }
+        node = nodesToSearch.pop();
       }
-      return out;
+      return false;
     }
-  };
-  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;
-          }
+    load(data) {
+      if (!(data && data.length)) return this;
+      if (data.length < this._minEntries) {
+        for (let i3 = 0; i3 < data.length; i3++) {
+          this.insert(data[i3]);
         }
-        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);
+        return this;
+      }
+      let node = this._build(data.slice(), 0, data.length - 1, 0);
+      if (!this.data.children.length) {
+        this.data = node;
+      } else if (this.data.height === node.height) {
+        this._splitRoot(this.data, node);
+      } else {
+        if (this.data.height < node.height) {
+          const tmpNode = this.data;
+          this.data = node;
+          node = tmpNode;
         }
-      });
-      if (pending === 0) {
-        done();
+        this._insert(node, this.data.height - node.height - 1, true);
       }
-      return;
+      return this;
     }
-    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>";
-      }
-      throw e;
+    insert(item) {
+      if (item) this._insert(item, this.data.height - 1);
+      return this;
     }
-    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);
-      }
-      return Parser.parse(tokens, opt);
-    } catch (e) {
-      onError(e);
+    clear() {
+      this.data = createNode([]);
+      return this;
     }
-  }
-  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);
-            } 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;
+    remove(item, equalsFn) {
+      if (!item) return this;
+      let node = this.data;
+      const bbox2 = this.toBBox(item);
+      const path = [];
+      const indexes = [];
+      let i3, parent, goingUp;
+      while (node || path.length) {
+        if (!node) {
+          node = path.pop();
+          parent = path[path.length - 1];
+          i3 = indexes.pop();
+          goingUp = true;
+        }
+        if (node.leaf) {
+          const index = findItem(item, node.children, equalsFn);
+          if (index !== -1) {
+            node.children.splice(index, 1);
+            path.push(node);
+            this._condense(path);
+            return this;
           }
-        });
-      }
-      if (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 (!goingUp && !node.leaf && contains(node, bbox2)) {
+          path.push(node);
+          indexes.push(i3);
+          i3 = 0;
+          parent = node;
+          node = node.children[0];
+        } else if (parent) {
+          i3++;
+          node = parent.children[i3];
+          goingUp = false;
+        } else node = null;
       }
-      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;
+      return this;
+    }
+    toBBox(item) {
+      return item;
+    }
+    compareMinX(a2, b2) {
+      return a2.minX - b2.minX;
+    }
+    compareMinY(a2, b2) {
+      return a2.minY - b2.minY;
+    }
+    toJSON() {
+      return this.data;
+    }
+    fromJSON(data) {
+      this.data = data;
+      return this;
+    }
+    _all(node, result) {
+      const nodesToSearch = [];
+      while (node) {
+        if (node.leaf) result.push(...node.children);
+        else nodesToSearch.push(...node.children);
+        node = nodesToSearch.pop();
       }
-      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));
-          }
-          return values;
-        };
+      return result;
+    }
+    _build(items, left, right, height) {
+      const N2 = right - left + 1;
+      let M2 = this._maxEntries;
+      let node;
+      if (N2 <= M2) {
+        node = createNode(items.slice(left, right + 1));
+        calcBBox(node, this.toBBox);
+        return node;
       }
-      if (hasExtensions) {
-        opts.extensions = extensions;
+      if (!height) {
+        height = Math.ceil(Math.log(N2) / Math.log(M2));
+        M2 = Math.ceil(N2 / Math.pow(M2, height - 1));
+      }
+      node = createNode([]);
+      node.leaf = false;
+      node.height = height;
+      const N22 = Math.ceil(N2 / M2);
+      const N1 = N22 * Math.ceil(Math.sqrt(M2));
+      multiSelect(items, left, right, N1, this.compareMinX);
+      for (let i3 = left; i3 <= right; i3 += N1) {
+        const right2 = Math.min(i3 + N1 - 1, right);
+        multiSelect(items, i3, right2, N22, this.compareMinY);
+        for (let j2 = i3; j2 <= right2; j2 += N22) {
+          const right3 = Math.min(j2 + N22 - 1, right2);
+          node.children.push(this._build(items, j2, right3, height - 1));
+        }
+      }
+      calcBBox(node, this.toBBox);
+      return node;
+    }
+    _chooseSubtree(bbox2, node, level, path) {
+      while (true) {
+        path.push(node);
+        if (node.leaf || path.length - 1 === level) break;
+        let minArea = Infinity;
+        let minEnlargement = Infinity;
+        let targetNode;
+        for (let i3 = 0; i3 < node.children.length; i3++) {
+          const child = node.children[i3];
+          const area = bboxArea(child);
+          const enlargement = enlargedArea(bbox2, child) - area;
+          if (enlargement < minEnlargement) {
+            minEnlargement = enlargement;
+            minArea = area < minArea ? area : minArea;
+            targetNode = child;
+          } else if (enlargement === minEnlargement) {
+            if (area < minArea) {
+              minArea = area;
+              targetNode = child;
+            }
+          }
+        }
+        node = targetNode || node.children[0];
       }
-      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));
-          }
-          for (const row of token.rows) {
-            for (const cell of row) {
-              values = values.concat(marked.walkTokens(cell.tokens, callback));
-            }
-          }
-          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 node;
+    }
+    _insert(item, level, isNode) {
+      const bbox2 = isNode ? item : this.toBBox(item);
+      const insertPath = [];
+      const node = this._chooseSubtree(bbox2, this.data, level, insertPath);
+      node.children.push(item);
+      extend2(node, bbox2);
+      while (level >= 0) {
+        if (insertPath[level].children.length > this._maxEntries) {
+          this._split(insertPath, level);
+          level--;
+        } else break;
+      }
+      this._adjustParentBBoxes(bbox2, insertPath, level);
+    }
+    // split overflowed node into two
+    _split(insertPath, level) {
+      const node = insertPath[level];
+      const M2 = node.children.length;
+      const m2 = this._minEntries;
+      this._chooseSplitAxis(node, m2, M2);
+      const splitIndex = this._chooseSplitIndex(node, m2, M2);
+      const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
+      newNode.height = node.height;
+      newNode.leaf = node.leaf;
+      calcBBox(node, this.toBBox);
+      calcBBox(newNode, this.toBBox);
+      if (level) insertPath[level - 1].children.push(newNode);
+      else this._splitRoot(node, newNode);
+    }
+    _splitRoot(node, newNode) {
+      this.data = createNode([node, newNode]);
+      this.data.height = node.height + 1;
+      this.data.leaf = false;
+      calcBBox(this.data, this.toBBox);
+    }
+    _chooseSplitIndex(node, m2, M2) {
+      let index;
+      let minOverlap = Infinity;
+      let minArea = Infinity;
+      for (let i3 = m2; i3 <= M2 - m2; i3++) {
+        const bbox1 = distBBox(node, 0, i3, this.toBBox);
+        const bbox2 = distBBox(node, i3, M2, this.toBBox);
+        const overlap = intersectionArea(bbox1, bbox2);
+        const area = bboxArea(bbox1) + bboxArea(bbox2);
+        if (overlap < minOverlap) {
+          minOverlap = overlap;
+          index = i3;
+          minArea = area < minArea ? area : minArea;
+        } else if (overlap === minOverlap) {
+          if (area < minArea) {
+            minArea = area;
+            index = i3;
+          }
+        }
+      }
+      return index || M2 - m2;
+    }
+    // sorts node children by the best axis for split
+    _chooseSplitAxis(node, m2, M2) {
+      const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
+      const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
+      const xMargin = this._allDistMargin(node, m2, M2, compareMinX);
+      const yMargin = this._allDistMargin(node, m2, M2, compareMinY);
+      if (xMargin < yMargin) node.children.sort(compareMinX);
+    }
+    // total margin of all possible split distributions where each node is at least m full
+    _allDistMargin(node, m2, M2, compare2) {
+      node.children.sort(compare2);
+      const toBBox = this.toBBox;
+      const leftBBox = distBBox(node, 0, m2, toBBox);
+      const rightBBox = distBBox(node, M2 - m2, M2, toBBox);
+      let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
+      for (let i3 = m2; i3 < M2 - m2; i3++) {
+        const child = node.children[i3];
+        extend2(leftBBox, node.leaf ? toBBox(child) : child);
+        margin += bboxMargin(leftBBox);
+      }
+      for (let i3 = M2 - m2 - 1; i3 >= m2; i3--) {
+        const child = node.children[i3];
+        extend2(rightBBox, node.leaf ? toBBox(child) : child);
+        margin += bboxMargin(rightBBox);
+      }
+      return margin;
+    }
+    _adjustParentBBoxes(bbox2, path, level) {
+      for (let i3 = level; i3 >= 0; i3--) {
+        extend2(path[i3], bbox2);
+      }
+    }
+    _condense(path) {
+      for (let i3 = path.length - 1, siblings; i3 >= 0; i3--) {
+        if (path[i3].children.length === 0) {
+          if (i3 > 0) {
+            siblings = path[i3 - 1].children;
+            siblings.splice(siblings.indexOf(path[i3]), 1);
+          } else this.clear();
+        } else calcBBox(path[i3], this.toBBox);
       }
     }
-    return values;
   };
-  marked.parseInline = function(src, opt) {
-    if (typeof src === "undefined" || src === null) {
-      throw new Error("marked.parseInline(): input parameter is undefined or null");
+  function findItem(item, items, equalsFn) {
+    if (!equalsFn) return items.indexOf(item);
+    for (let i3 = 0; i3 < items.length; i3++) {
+      if (equalsFn(item, items[i3])) return i3;
     }
-    if (typeof src !== "string") {
-      throw new Error("marked.parseInline(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected");
+    return -1;
+  }
+  function calcBBox(node, toBBox) {
+    distBBox(node, 0, node.children.length, toBBox, node);
+  }
+  function distBBox(node, k2, p2, toBBox, destNode) {
+    if (!destNode) destNode = createNode(null);
+    destNode.minX = Infinity;
+    destNode.minY = Infinity;
+    destNode.maxX = -Infinity;
+    destNode.maxY = -Infinity;
+    for (let i3 = k2; i3 < p2; i3++) {
+      const child = node.children[i3];
+      extend2(destNode, node.leaf ? toBBox(child) : child);
     }
-    opt = merge2({}, marked.defaults, opt || {});
-    checkSanitizeDeprecation(opt);
-    try {
-      const tokens = Lexer.lexInline(src, opt);
-      if (opt.walkTokens) {
-        marked.walkTokens(tokens, opt.walkTokens);
-      }
-      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>";
-      }
-      throw e;
+    return destNode;
+  }
+  function extend2(a2, b2) {
+    a2.minX = Math.min(a2.minX, b2.minX);
+    a2.minY = Math.min(a2.minY, b2.minY);
+    a2.maxX = Math.max(a2.maxX, b2.maxX);
+    a2.maxY = Math.max(a2.maxY, b2.maxY);
+    return a2;
+  }
+  function compareNodeMinX(a2, b2) {
+    return a2.minX - b2.minX;
+  }
+  function compareNodeMinY(a2, b2) {
+    return a2.minY - b2.minY;
+  }
+  function bboxArea(a2) {
+    return (a2.maxX - a2.minX) * (a2.maxY - a2.minY);
+  }
+  function bboxMargin(a2) {
+    return a2.maxX - a2.minX + (a2.maxY - a2.minY);
+  }
+  function enlargedArea(a2, b2) {
+    return (Math.max(b2.maxX, a2.maxX) - Math.min(b2.minX, a2.minX)) * (Math.max(b2.maxY, a2.maxY) - Math.min(b2.minY, a2.minY));
+  }
+  function intersectionArea(a2, b2) {
+    const minX = Math.max(a2.minX, b2.minX);
+    const minY = Math.max(a2.minY, b2.minY);
+    const maxX = Math.min(a2.maxX, b2.maxX);
+    const maxY = Math.min(a2.maxY, b2.maxY);
+    return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
+  }
+  function contains(a2, b2) {
+    return a2.minX <= b2.minX && a2.minY <= b2.minY && b2.maxX <= a2.maxX && b2.maxY <= a2.maxY;
+  }
+  function intersects(a2, b2) {
+    return b2.minX <= a2.maxX && b2.minY <= a2.maxY && b2.maxX >= a2.minX && b2.maxY >= a2.minY;
+  }
+  function createNode(children2) {
+    return {
+      children: children2,
+      height: 1,
+      leaf: true,
+      minX: Infinity,
+      minY: Infinity,
+      maxX: -Infinity,
+      maxY: -Infinity
+    };
+  }
+  function multiSelect(arr, left, right, n3, compare2) {
+    const stack = [left, right];
+    while (stack.length) {
+      right = stack.pop();
+      left = stack.pop();
+      if (right - left <= n3) continue;
+      const mid = left + Math.ceil((right - left) / n3 / 2) * n3;
+      quickselect2(arr, mid, left, right, compare2);
+      stack.push(left, mid, mid, right);
     }
-  };
-  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) {
+  // 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((text) => new DOMParser().parseFromString(text, 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();
     }
   }
-  function abortUnwantedRequests3(cache, tiles) {
-    Object.keys(cache.inflightTile).forEach((k) => {
-      let wanted = tiles.find((tile) => k === tile.id);
+  function abortUnwantedRequests(cache, tiles) {
+    Object.keys(cache.inflightTile).forEach((k2) => {
+      const wanted = tiles.find((tile) => k2 === tile.id);
       if (!wanted) {
-        abortRequest3(cache.inflightTile[k]);
-        delete cache.inflightTile[k];
+        abortRequest(cache.inflightTile[k2]);
+        delete cache.inflightTile[k2];
       }
     });
   }
-  function encodeIssueRtree3(d) {
-    return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
+  function encodeIssueRtree(d2) {
+    return { minX: d2.loc[0], minY: d2.loc[1], maxX: d2.loc[0], maxY: d2.loc[1], data: d2 };
   }
-  function updateRtree3(item, replace) {
-    _cache3.rtree.remove(item, (a, b) => a.data.id === b.data.id);
+  function updateRtree(item, replace) {
+    _cache.rtree.remove(item, (a2, b2) => a2.data.id === b2.data.id);
     if (replace) {
-      _cache3.rtree.insert(item);
+      _cache.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;
+  function tokenReplacements(d2) {
+    if (!(d2 instanceof QAItem)) return;
+    const replacements = {};
+    const issueTemplate = _krData.errorTypes[d2.whichType];
+    if (!issueTemplate) {
+      console.log("No Template: ", d2.whichType);
+      console.log("  ", d2.description);
+      return;
+    }
+    if (!issueTemplate.regex) return;
+    const errorRegex = new RegExp(issueTemplate.regex, "i");
+    const errorMatch = errorRegex.exec(d2.description);
+    if (!errorMatch) {
+      console.log("Unmatched: ", d2.whichType);
+      console.log("  ", d2.description);
+      console.log("  ", errorRegex);
+      return;
+    }
+    for (let i3 = 1; i3 < errorMatch.length; i3++) {
+      let capture = errorMatch[i3];
+      let idType;
+      idType = "IDs" in issueTemplate ? issueTemplate.IDs[i3 - 1] : "";
+      if (idType && capture) {
+        capture = parseError(capture, idType);
+      } else {
+        const compare2 = capture.toLowerCase();
+        if (_krData.localizeStrings[compare2]) {
+          capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare2]);
+        } else {
+          capture = unescape_default(capture);
+        }
+      }
+      replacements["var" + i3] = capture;
+    }
+    return replacements;
   }
-  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], []);
+  function parseError(capture, idType) {
+    const compare2 = capture.toLowerCase();
+    if (_krData.localizeStrings[compare2]) {
+      capture = _t("QA.keepRight.error_parts." + _krData.localizeStrings[compare2]);
+    }
+    switch (idType) {
+      // link a string like "this node"
+      case "this":
+        capture = linkErrorObject(capture);
+        break;
+      case "url":
+        capture = linkURL(capture);
+        break;
+      // link an entity ID
+      case "n":
+      case "w":
+      case "r":
+        capture = linkEntity(idType + capture);
+        break;
+      // some errors have more complex ID lists/variance
+      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 linkErrorObject(d2) {
+      return { html: '<a class="error_object_link">'.concat(d2, "</a>") };
+    }
+    function linkEntity(d2) {
+      return { html: '<a class="error_entity_link">'.concat(d2, "</a>") };
+    }
+    function linkURL(d2) {
+      return { html: '<a class="kr_external_link" target="_blank" href="'.concat(d2, '">').concat(d2, "</a>") };
+    }
+    function parse211(capture2) {
+      let newList = [];
+      const items = capture2.split(", ");
+      items.forEach((item) => {
+        let id2 = linkEntity("n" + item.slice(1));
+        newList.push(id2);
       });
-      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;
+      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(
+            linkEntity("w" + match[1]) + " " + _t("QA.keepRight.errorTypes.231.layer", { layer: match[2] })
+          );
+        }
+      });
+      return newList.join(", ");
+    }
+    function parse294(capture2) {
+      let newList = [];
+      const items = capture2.split(",");
+      items.forEach((item) => {
+        item = item.split(" ");
+        const role = '"'.concat(item[0], '"');
+        const idType2 = item[1].slice(0, 1);
+        let id2 = item[2].slice(1);
+        id2 = linkEntity(idType2 + id2);
+        newList.push("".concat(role, " ").concat(item[1], " ").concat(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] });
       }
-      _cache3 = {
+      return "";
+    }
+    function parse20(capture2) {
+      let newList = [];
+      const items = capture2.split(",");
+      items.forEach((item) => {
+        const id2 = linkEntity("n" + item.slice(1));
+        newList.push(id2);
+      });
+      return newList.join(", ");
+    }
+  }
+  var keepRight_default = {
+    title: "keepRight",
+    init() {
+      _mainFileFetcher.get("keepRight").then((d2) => _krData = d2);
+      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_rbush3.default(),
-        strings: _strings,
-        colors: _colors
+        rtree: new RBush()
       };
     },
+    // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
     loadIssues(projection2) {
-      let params = {
-        item: _osmoseData.items
+      const options2 = {
+        format: "geojson",
+        ch: _krRuleset
       };
-      let tiles = tiler3.zoomExtent([_tileZoom3, _tileZoom3]).getTiles(projection2);
-      abortUnwantedRequests3(_cache3, tiles);
+      const tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection2);
+      abortUnwantedRequests(_cache, 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;
+        if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
+        const [left, top, right, bottom] = tile.extent.rectangle();
+        const params = Object.assign({}, options2, { left, bottom, right, top });
+        const url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
+        const controller = new AbortController();
+        _cache.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));
+          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: ".concat(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~".concat(description);
+                break;
+              case "300":
+                description = "This highway is missing a maxspeed tag";
+                break;
+              case "411":
+              case "412":
+              case "413":
+                description = "This feature~".concat(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 d2 = new QAItem(loc, this, itemType, id2, {
+              comment,
+              description,
+              whichType,
+              parentIssueType,
+              severity: whichTemplate.severity || "error",
+              objectId,
+              objectType,
+              schema,
+              title
             });
-          }
-          dispatch4.call("loaded");
+            d2.replacements = tokenReplacements(d2);
+            _cache.data[id2] = d2;
+            _cache.rtree.insert(encodeIssueRtree(d2));
+          });
+          dispatch2.call("loaded");
         }).catch(() => {
-          delete _cache3.inflightTile[tile.id];
-          _cache3.loadedTile[tile.id] = true;
+          delete _cache.inflightTile[tile.id];
+          _cache.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]);
+    postUpdate(d2, callback) {
+      if (_cache.inflightPost[d2.id]) {
+        return callback({ message: "Error update already inflight", status: -2 }, d2);
       }
-      if (!(locale2 in _cache3.strings)) {
-        _cache3.strings[locale2] = {};
+      const params = { schema: d2.schema, id: d2.id };
+      if (d2.newStatus) {
+        params.st = d2.newStatus;
       }
-      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);
+      if (d2.newComment !== void 0) {
+        params.co = d2.newComment;
       }
-      const url = `${_osmoseUrlRoot}/issue/${issue.id}/${issue.newStatus}`;
+      const url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
       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;
+      _cache.inflightPost[d2.id] = controller;
+      json_default(url, { signal: controller.signal }).finally(() => {
+        delete _cache.inflightPost[d2.id];
+        if (d2.newStatus === "ignore") {
+          this.removeItem(d2);
+        } else if (d2.newStatus === "ignore_t") {
+          this.removeItem(d2);
+          _cache.closed["".concat(d2.schema, ":").concat(d2.id)] = true;
+        } else {
+          d2 = this.replaceItem(d2.update({
+            comment: d2.newComment,
+            newComment: void 0,
+            newState: void 0
+          }));
         }
-        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);
+        if (callback) callback(null, d2);
       });
     },
+    // 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 bbox = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
-      return _cache3.rtree.search(bbox).map((d) => d.data);
+      const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+      return _cache.rtree.search(bbox2).map((d2) => d2.data);
     },
+    // Get a QAItem from cache
+    // NOTE: Don't change method name until UI v3 is merged
     getError(id2) {
-      return _cache3.data[id2];
-    },
-    getIcon(itemType) {
-      return _osmoseData.icons[itemType];
+      return _cache.data[id2];
     },
+    // Replace a single QAItem in the cache
     replaceItem(item) {
-      if (!(item instanceof QAItem) || !item.id)
-        return;
-      _cache3.data[item.id] = item;
-      updateRtree3(encodeIssueRtree3(item), true);
+      if (!(item instanceof QAItem) || !item.id) return;
+      _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 _cache3.data[item.id];
-      updateRtree3(encodeIssueRtree3(item), false);
+      if (!(item instanceof QAItem) || !item.id) return;
+      delete _cache.data[item.id];
+      updateRtree(encodeIssueRtree(item), false);
     },
-    getClosedCounts() {
-      return _cache3.closed;
+    issueURL(item) {
+      return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
     },
-    itemURL(item) {
-      return `https://osmose.openstreetmap.fr/en/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();
     }
   };
 
-  // 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);
-    });
+  // node_modules/marked/lib/marked.esm.js
+  function _getDefaults() {
+    return {
+      async: false,
+      breaks: false,
+      extensions: null,
+      gfm: true,
+      hooks: null,
+      pedantic: false,
+      renderer: null,
+      silent: false,
+      tokenizer: null,
+      walkTokens: null
+    };
   }
-  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);
+  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 escape$1(html3, encode) {
+    if (encode) {
+      if (escapeTest.test(html3)) {
+        return html3.replace(escapeReplace, getEscapeReplacement);
       }
-      cache.loaded[tileId] = true;
-      delete cache.inflight[tileId];
-      return response.arrayBuffer();
-    }).then(function(data) {
-      if (!data) {
-        throw new Error("No Data");
+    } else {
+      if (escapeTestNoEncode.test(html3)) {
+        return html3.replace(escapeReplaceNoEncode, getEscapeReplacement);
       }
-      loadTileDataToCache(data, tile, which);
-      if (which === "images") {
-        dispatch5.call("loadedImages");
-      } else if (which === "signs") {
-        dispatch5.call("loadedSigns");
-      } else if (which === "points") {
-        dispatch5.call("loadedMapFeatures");
+    }
+    return html3;
+  }
+  var caret = /(^|[^\[])\^/g;
+  function edit(regex, opt) {
+    let source = typeof regex === "string" ? regex : regex.source;
+    opt = opt || "";
+    const obj = {
+      replace: (name, val) => {
+        let valSource = typeof val === "string" ? val : val.source;
+        valSource = valSource.replace(caret, "$1");
+        source = source.replace(name, valSource);
+        return obj;
+      },
+      getRegex: () => {
+        return new RegExp(source, opt);
       }
-    }).catch(function() {
-      cache.loaded[tileId] = true;
-      delete cache.inflight[tileId];
-    });
+    };
+    return obj;
   }
-  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
-        });
+  function cleanUrl(href) {
+    try {
+      href = encodeURI(href).replace(/%25/g, "%");
+    } catch {
+      return null;
+    }
+    return href;
+  }
+  var noopTest = { exec: () => null };
+  function splitCells(tableRow, count) {
+    const row = tableRow.replace(/\|/g, (match, offset, str) => {
+      let escaped = false;
+      let curr = offset;
+      while (--curr >= 0 && str[curr] === "\\")
+        escaped = !escaped;
+      if (escaped) {
+        return "|";
+      } else {
+        return " |";
       }
-      if (cache.rtree) {
-        cache.rtree.load(features2);
+    }), cells = row.split(/ \|/);
+    let i3 = 0;
+    if (!cells[0].trim()) {
+      cells.shift();
+    }
+    if (cells.length > 0 && !cells[cells.length - 1].trim()) {
+      cells.pop();
+    }
+    if (count) {
+      if (cells.length > count) {
+        cells.splice(count);
+      } else {
+        while (cells.length < count)
+          cells.push("");
       }
     }
-    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];
+    for (; i3 < cells.length; i3++) {
+      cells[i3] = cells[i3].trim().replace(/\\\|/g, "|");
+    }
+    return cells;
+  }
+  function rtrim(str, c2, invert) {
+    const l2 = str.length;
+    if (l2 === 0) {
+      return "";
+    }
+    let suffLen = 0;
+    while (suffLen < l2) {
+      const currChar = str.charAt(l2 - suffLen - 1);
+      if (currChar === c2 && !invert) {
+        suffLen++;
+      } else if (currChar !== c2 && invert) {
+        suffLen++;
+      } else {
+        break;
+      }
+    }
+    return str.slice(0, l2 - suffLen);
+  }
+  function findClosingBracket(str, b2) {
+    if (str.indexOf(b2[1]) === -1) {
+      return -1;
+    }
+    let level = 0;
+    for (let i3 = 0; i3 < str.length; i3++) {
+      if (str[i3] === "\\") {
+        i3++;
+      } else if (str[i3] === b2[0]) {
+        level++;
+      } else if (str[i3] === b2[1]) {
+        level--;
+        if (level < 0) {
+          return i3;
         }
       }
     }
-    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
-        };
-        features2.push({
-          minX: loc[0],
-          minY: loc[1],
-          maxX: loc[0],
-          maxY: loc[1],
-          data: d
-        });
+    return -1;
+  }
+  function outputLink(cap, link3, raw, lexer2) {
+    const href = link3.href;
+    const title = link3.title ? escape$1(link3.title) : null;
+    const text = cap[1].replace(/\\([\[\]])/g, "$1");
+    if (cap[0].charAt(0) !== "!") {
+      lexer2.state.inLink = true;
+      const token = {
+        type: "link",
+        raw,
+        href,
+        title,
+        text,
+        tokens: lexer2.inlineTokens(text)
+      };
+      lexer2.state.inLink = false;
+      return token;
+    }
+    return {
+      type: "image",
+      raw,
+      href,
+      title,
+      text: escape$1(text)
+    };
+  }
+  function indentCodeCompensation(raw, text) {
+    const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
+    if (matchIndentToCode === null) {
+      return text;
+    }
+    const indentToCode = matchIndentToCode[1];
+    return text.split("\n").map((node) => {
+      const matchIndentInNode = node.match(/^\s+/);
+      if (matchIndentInNode === null) {
+        return node;
       }
-      if (cache.rtree) {
-        cache.rtree.load(features2);
+      const [indentInNode] = matchIndentInNode;
+      if (indentInNode.length >= indentToCode.length) {
+        return node.slice(indentToCode.length);
       }
+      return node;
+    }).join("\n");
+  }
+  var _Tokenizer = class {
+    // set by the lexer
+    constructor(options2) {
+      __publicField(this, "options");
+      __publicField(this, "rules");
+      // set by the lexer
+      __publicField(this, "lexer");
+      this.options = options2 || _defaults;
     }
-    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
+    space(src) {
+      const cap = this.rules.block.newline.exec(src);
+      if (cap && cap[0].length > 0) {
+        return {
+          type: "space",
+          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);
+    code(src) {
+      const cap = this.rules.block.code.exec(src);
+      if (cap) {
+        const text = cap[0].replace(/^ {1,4}/gm, "");
+        return {
+          type: "code",
+          raw: cap[0],
+          codeBlockStyle: "indented",
+          text: !this.options.pedantic ? rtrim(text, "\n") : text
+        };
       }
-      return response.json();
-    }).then(function(result) {
-      if (!result) {
-        return [];
+    }
+    fences(src) {
+      const cap = this.rules.block.fences.exec(src);
+      if (cap) {
+        const raw = cap[0];
+        const text = indentCodeCompensation(raw, cap[3] || "");
+        return {
+          type: "code",
+          raw,
+          lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : cap[2],
+          text
+        };
       }
-      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();
+    }
+    heading(src) {
+      const cap = this.rules.block.heading.exec(src);
+      if (cap) {
+        let text = cap[2].trim();
+        if (/#$/.test(text)) {
+          const trimmed = rtrim(text, "#");
+          if (this.options.pedantic) {
+            text = trimmed.trim();
+          } else if (!trimmed || / $/.test(trimmed)) {
+            text = trimmed.trim();
+          }
+        }
+        return {
+          type: "heading",
+          raw: cap[0],
+          depth: cap[1].length,
+          text,
+          tokens: this.lexer.inline(text)
+        };
       }
-      this.event = utilRebind(this, dispatch5, "on");
-    },
-    reset: function() {
-      if (_mlyCache) {
-        Object.values(_mlyCache.requests.inflight).forEach(function(request3) {
-          request3.abort();
-        });
+    }
+    hr(src) {
+      const cap = this.rules.block.hr.exec(src);
+      if (cap) {
+        return {
+          type: "hr",
+          raw: rtrim(cap[0], "\n")
+        };
       }
-      _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]);
+    }
+    blockquote(src) {
+      const cap = this.rules.block.blockquote.exec(src);
+      if (cap) {
+        let lines = rtrim(cap[0], "\n").split("\n");
+        let raw = "";
+        let text = "";
+        const tokens = [];
+        while (lines.length > 0) {
+          let inBlockquote = false;
+          const currentLines = [];
+          let i3;
+          for (i3 = 0; i3 < lines.length; i3++) {
+            if (/^ {0,3}>/.test(lines[i3])) {
+              currentLines.push(lines[i3]);
+              inBlockquote = true;
+            } else if (!inBlockquote) {
+              currentLines.push(lines[i3]);
+            } else {
+              break;
+            }
+          }
+          lines = lines.slice(i3);
+          const currentRaw = currentLines.join("\n");
+          const currentText = currentRaw.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, "\n    $1").replace(/^ {0,3}>[ \t]?/gm, "");
+          raw = raw ? "".concat(raw, "\n").concat(currentRaw) : currentRaw;
+          text = text ? "".concat(text, "\n").concat(currentText) : currentText;
+          const top = this.lexer.state.top;
+          this.lexer.state.top = true;
+          this.lexer.blockTokens(currentText, tokens, true);
+          this.lexer.state.top = top;
+          if (lines.length === 0) {
+            break;
+          }
+          const lastToken = tokens[tokens.length - 1];
+          if ((lastToken == null ? void 0 : lastToken.type) === "code") {
+            break;
+          } else if ((lastToken == null ? void 0 : lastToken.type) === "blockquote") {
+            const oldToken = lastToken;
+            const newText = oldToken.raw + "\n" + lines.join("\n");
+            const newToken = this.blockquote(newText);
+            tokens[tokens.length - 1] = newToken;
+            raw = raw.substring(0, raw.length - oldToken.raw.length) + newToken.raw;
+            text = text.substring(0, text.length - oldToken.text.length) + newToken.text;
+            break;
+          } else if ((lastToken == null ? void 0 : lastToken.type) === "list") {
+            const oldToken = lastToken;
+            const newText = oldToken.raw + "\n" + lines.join("\n");
+            const newToken = this.list(newText);
+            tokens[tokens.length - 1] = newToken;
+            raw = raw.substring(0, raw.length - lastToken.raw.length) + newToken.raw;
+            text = text.substring(0, text.length - oldToken.raw.length) + newToken.raw;
+            lines = newText.substring(tokens[tokens.length - 1].raw.length).split("\n");
+            continue;
+          }
         }
-      });
-      return 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();
-        }
-        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();
-      }
-    },
-    showFeatureDetections: function(value) {
-      _mlyShowFeatureDetections = value;
-      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
-        this.resetTags();
+        return {
+          type: "blockquote",
+          raw,
+          tokens,
+          text
+        };
       }
-    },
-    showSignDetections: function(value) {
-      _mlyShowSignDetections = value;
-      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
-        this.resetTags();
+    }
+    list(src) {
+      let cap = this.rules.block.list.exec(src);
+      if (cap) {
+        let bull = cap[1].trim();
+        const isordered = bull.length > 1;
+        const list2 = {
+          type: "list",
+          raw: "",
+          ordered: isordered,
+          start: isordered ? +bull.slice(0, -1) : "",
+          loose: false,
+          items: []
+        };
+        bull = isordered ? "\\d{1,9}\\".concat(bull.slice(-1)) : "\\".concat(bull);
+        if (this.options.pedantic) {
+          bull = isordered ? bull : "[*+-]";
+        }
+        const itemRegex = new RegExp("^( {0,3}".concat(bull, ")((?:[    ][^\\n]*)?(?:\\n|$))"));
+        let endsWithBlankLine = false;
+        while (src) {
+          let endEarly = false;
+          let raw = "";
+          let itemContents = "";
+          if (!(cap = itemRegex.exec(src))) {
+            break;
+          }
+          if (this.rules.block.hr.test(src)) {
+            break;
+          }
+          raw = cap[0];
+          src = src.substring(raw.length);
+          let line = cap[2].split("\n", 1)[0].replace(/^\t+/, (t2) => " ".repeat(3 * t2.length));
+          let nextLine = src.split("\n", 1)[0];
+          let blankLine = !line.trim();
+          let indent = 0;
+          if (this.options.pedantic) {
+            indent = 2;
+            itemContents = line.trimStart();
+          } else if (blankLine) {
+            indent = cap[1].length + 1;
+          } else {
+            indent = cap[2].search(/[^ ]/);
+            indent = indent > 4 ? 1 : indent;
+            itemContents = line.slice(indent);
+            indent += cap[1].length;
+          }
+          if (blankLine && /^ *$/.test(nextLine)) {
+            raw += nextLine + "\n";
+            src = src.substring(nextLine.length + 1);
+            endEarly = true;
+          }
+          if (!endEarly) {
+            const nextBulletRegex = new RegExp("^ {0,".concat(Math.min(3, indent - 1), "}(?:[*+-]|\\d{1,9}[.)])((?:[   ][^\\n]*)?(?:\\n|$))"));
+            const hrRegex = new RegExp("^ {0,".concat(Math.min(3, indent - 1), "}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)"));
+            const fencesBeginRegex = new RegExp("^ {0,".concat(Math.min(3, indent - 1), "}(?:```|~~~)"));
+            const headingBeginRegex = new RegExp("^ {0,".concat(Math.min(3, indent - 1), "}#"));
+            while (src) {
+              const rawLine = src.split("\n", 1)[0];
+              nextLine = rawLine;
+              if (this.options.pedantic) {
+                nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, "  ");
+              }
+              if (fencesBeginRegex.test(nextLine)) {
+                break;
+              }
+              if (headingBeginRegex.test(nextLine)) {
+                break;
+              }
+              if (nextBulletRegex.test(nextLine)) {
+                break;
+              }
+              if (hrRegex.test(src)) {
+                break;
+              }
+              if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) {
+                itemContents += "\n" + nextLine.slice(indent);
+              } 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;
+              }
+              if (!blankLine && !nextLine.trim()) {
+                blankLine = true;
+              }
+              raw += rawLine + "\n";
+              src = src.substring(rawLine.length + 1);
+              line = nextLine.slice(indent);
+            }
+          }
+          if (!list2.loose) {
+            if (endsWithBlankLine) {
+              list2.loose = true;
+            } else if (/\n *\n *$/.test(raw)) {
+              endsWithBlankLine = true;
+            }
+          }
+          let istask = null;
+          let ischecked;
+          if (this.options.gfm) {
+            istask = /^\[[ xX]\] /.exec(itemContents);
+            if (istask) {
+              ischecked = istask[0] !== "[ ] ";
+              itemContents = itemContents.replace(/^\[[ xX]\] +/, "");
+            }
+          }
+          list2.items.push({
+            type: "list_item",
+            raw,
+            task: !!istask,
+            checked: ischecked,
+            loose: false,
+            text: itemContents,
+            tokens: []
+          });
+          list2.raw += raw;
+        }
+        list2.items[list2.items.length - 1].raw = list2.items[list2.items.length - 1].raw.trimEnd();
+        list2.items[list2.items.length - 1].text = list2.items[list2.items.length - 1].text.trimEnd();
+        list2.raw = list2.raw.trimEnd();
+        for (let i3 = 0; i3 < list2.items.length; i3++) {
+          this.lexer.state.top = false;
+          list2.items[i3].tokens = this.lexer.blockTokens(list2.items[i3].text, []);
+          if (!list2.loose) {
+            const spacers = list2.items[i3].tokens.filter((t2) => t2.type === "space");
+            const hasMultipleLineBreaks = spacers.length > 0 && spacers.some((t2) => /\n.*\n/.test(t2.raw));
+            list2.loose = hasMultipleLineBreaks;
+          }
+        }
+        if (list2.loose) {
+          for (let i3 = 0; i3 < list2.items.length; i3++) {
+            list2.items[i3].loose = true;
+          }
+        }
+        return list2;
       }
-    },
-    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()]);
+    }
+    html(src) {
+      const cap = this.rules.block.html.exec(src);
+      if (cap) {
+        const token = {
+          type: "html",
+          block: true,
+          raw: cap[0],
+          pre: cap[1] === "pre" || cap[1] === "script" || cap[1] === "style",
+          text: cap[0]
+        };
+        return token;
       }
-      if (toDate) {
-        filter2.push([">=", "capturedAt", new Date(toDate).getTime()]);
+    }
+    def(src) {
+      const cap = this.rules.block.def.exec(src);
+      if (cap) {
+        const tag2 = cap[1].toLowerCase().replace(/\s+/g, " ");
+        const href = cap[2] ? cap[2].replace(/^<(.*)>$/, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "";
+        const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : cap[3];
+        return {
+          type: "def",
+          tag: tag2,
+          raw: cap[0],
+          href,
+          title
+        };
       }
-      if (_mlyViewer) {
-        _mlyViewer.setFilter(filter2);
+    }
+    table(src) {
+      const cap = this.rules.block.table.exec(src);
+      if (!cap) {
+        return;
       }
-      _mlyViewerFilter = filter2;
-      return filter2;
-    },
-    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();
+      if (!/[:|]/.test(cap[2])) {
+        return;
       }
-      return this;
-    },
-    hideViewer: function(context) {
-      _mlyActiveImage = null;
-      if (!_mlyFallback && _mlyViewer) {
-        _mlyViewer.getComponent("sequence").stop();
+      const headers = splitCells(cap[1]);
+      const aligns = cap[2].replace(/^\||\| *$/g, "").split("|");
+      const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, "").split("\n") : [];
+      const item = {
+        type: "table",
+        raw: cap[0],
+        header: [],
+        align: [],
+        rows: []
+      };
+      if (headers.length !== aligns.length) {
+        return;
       }
-      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;
+      for (const align of aligns) {
+        if (/^ *-+: *$/.test(align)) {
+          item.align.push("right");
+        } else if (/^ *:-+: *$/.test(align)) {
+          item.align.push("center");
+        } else if (/^ *:-+ *$/.test(align)) {
+          item.align.push("left");
         } else {
-          delete hash.photo;
+          item.align.push(null);
         }
-        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"
-      };
-      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
-        };
+      for (let i3 = 0; i3 < headers.length; i3++) {
+        item.header.push({
+          text: headers[i3],
+          tokens: this.lexer.inline(headers[i3]),
+          header: true,
+          align: item.align[i3]
+        });
       }
-      _mlyViewer = new mapillary.Viewer(opts);
-      _mlyViewer.on("image", imageChanged);
-      _mlyViewer.on("bearing", bearingChanged);
-      if (_mlyViewerFilter) {
-        _mlyViewer.setFilter(_mlyViewerFilter);
+      for (const row of rows) {
+        item.rows.push(splitCells(row, item.header.length).map((cell, i3) => {
+          return {
+            text: cell,
+            tokens: this.lexer.inline(cell),
+            header: false,
+            align: item.align[i3]
+          };
+        }));
       }
-      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");
+      return item;
+    }
+    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 bearingChanged(e) {
-        dispatch5.call("bearingChanged", void 0, e);
+    }
+    paragraph(src) {
+      const cap = this.rules.block.paragraph.exec(src);
+      if (cap) {
+        const text = cap[1].charAt(cap[1].length - 1) === "\n" ? cap[1].slice(0, -1) : cap[1];
+        return {
+          type: "paragraph",
+          raw: cap[0],
+          text,
+          tokens: this.lexer.inline(text)
+        };
       }
-    },
-    selectImage: function(context, imageId) {
-      if (_mlyViewer && imageId) {
-        _mlyViewer.moveTo(imageId).catch(function(e) {
-          console.error("mly3", e);
-        });
+    }
+    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])
+        };
       }
-      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
+    }
+    escape(src) {
+      const cap = this.rules.inline.escape.exec(src);
+      if (cap) {
+        return {
+          type: "escape",
+          raw: cap[0],
+          text: escape$1(cap[1])
         };
-      } else {
-        _mlyActiveImage = null;
       }
-    },
-    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] = [];
-            }
-            cache.forImageId[imageId].push({
-              geometry: detection.geometry,
-              id: detection.id,
-              image_id: imageId,
-              value: detection.value
-            });
-          });
-          showDetections(_mlyCache.image_detections.forImageId[imageId] || []);
-        });
+    }
+    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: "html",
+          raw: cap[0],
+          inLink: this.lexer.state.inLink,
+          inRawBlock: this.lexer.state.inRawBlock,
+          block: false,
+          text: cap[0]
+        };
       }
-      function showDetections(detections) {
-        const tagComponent = _mlyViewer.getComponent("tag");
-        detections.forEach(function(data) {
-          const tag = makeTag(data);
-          if (tag) {
-            tagComponent.add([tag]);
+    }
+    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;
           }
-        });
-      }
-      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];
+          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] = "";
           }
-          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);
+        let href = cap[2];
+        let title = "";
+        if (this.options.pedantic) {
+          const link3 = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
+          if (link3) {
+            href = link3[1];
+            title = link3[3];
+          }
+        } else {
+          title = cap[3] ? cap[3].slice(1, -1) : "";
         }
-        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
+        href = href.trim();
+        if (/^</.test(href)) {
+          if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
+            href = href.slice(1);
+          } else {
+            href = href.slice(1, -1);
           }
-        );
-        return tag;
+        }
+        return outputLink(cap, {
+          href: href ? href.replace(this.rules.inline.anyPunctuation, "$1") : href,
+          title: title ? title.replace(this.rules.inline.anyPunctuation, "$1") : title
+        }, cap[0], this.lexer);
       }
-    },
-    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);
+    reflink(src, links) {
+      let cap;
+      if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
+        const linkString = (cap[2] || cap[1]).replace(/\s+/g, " ");
+        const link3 = links[linkString.toLowerCase()];
+        if (!link3) {
+          const text = cap[0].charAt(0);
+          return {
+            type: "text",
+            raw: text,
+            text
+          };
+        }
+        return outputLink(cap, link3, cap[0], this.lexer);
       }
-      return parts.join(":");
     }
-    function generateKey() {
-      return this.id + ":" + Date.now().toString();
+    emStrong(src, maskedSrc, prevChar = "") {
+      let match = this.rules.inline.emStrongLDelim.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.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
+        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 lastCharLength = [...match[0]][0].length;
+          const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);
+          if (Math.min(lLength, rLength) % 2) {
+            const text2 = raw.slice(1, -1);
+            return {
+              type: "em",
+              raw,
+              text: text2,
+              tokens: this.lexer.inlineTokens(text2)
+            };
+          }
+          const text = raw.slice(2, -2);
+          return {
+            type: "strong",
+            raw,
+            text,
+            tokens: this.lexer.inlineTokens(text)
+          };
+        }
+      }
     }
-    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;
+    codespan(src) {
+      const cap = this.rules.inline.code.exec(src);
+      if (cap) {
+        let text = cap[2].replace(/\n/g, " ");
+        const hasNonSpaceChars = /[^ ]/.test(text);
+        const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
+        if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
+          text = text.substring(1, text.length - 1);
         }
-      });
-      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;
+        text = escape$1(text, true);
+        return {
+          type: "codespan",
+          raw: cap[0],
+          text
         };
-      },
-      greaterThanEqual: function(greaterThanEqual) {
-        var key = Object.keys(greaterThanEqual)[0];
-        var value = greaterThanEqual[key];
-        return function(tags) {
-          return tags[key] >= value;
+      }
+    }
+    br(src) {
+      const cap = this.rules.inline.br.exec(src);
+      if (cap) {
+        return {
+          type: "br",
+          raw: cap[0]
         };
-      },
-      lessThan: function(lessThan) {
-        var key = Object.keys(lessThan)[0];
-        var value = lessThan[key];
-        return function(tags) {
-          return tags[key] < value;
+      }
+    }
+    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])
         };
-      },
-      lessThanEqual: function(lessThanEqual) {
-        var key = Object.keys(lessThanEqual)[0];
-        var value = lessThanEqual[key];
-        return function(tags) {
-          return tags[key] <= value;
+      }
+    }
+    autolink(src) {
+      const cap = this.rules.inline.autolink.exec(src);
+      if (cap) {
+        let text, href;
+        if (cap[2] === "@") {
+          text = escape$1(cap[1]);
+          href = "mailto:" + text;
+        } else {
+          text = escape$1(cap[1]);
+          href = text;
+        }
+        return {
+          type: "link",
+          raw: cap[0],
+          text,
+          href,
+          tokens: [
+            {
+              type: "text",
+              raw: text,
+              text
+            }
+          ]
         };
-      },
-      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]);
+      }
+    }
+    url(src) {
+      var _a3, _b3;
+      let cap;
+      if (cap = this.rules.inline.url.exec(src)) {
+        let text, href;
+        if (cap[2] === "@") {
+          text = escape$1(cap[0]);
+          href = "mailto:" + text;
+        } else {
+          let prevCapZero;
+          do {
+            prevCapZero = cap[0];
+            cap[0] = (_b3 = (_a3 = this.rules.inline._backpedal.exec(cap[0])) == null ? void 0 : _a3[0]) != null ? _b3 : "";
+          } while (prevCapZero !== cap[0]);
+          text = escape$1(cap[0]);
+          if (cap[1] === "www.") {
+            href = "http://" + cap[0];
+          } else {
+            href = cap[0];
+          }
+        }
+        return {
+          type: "link",
+          raw: cap[0],
+          text,
+          href,
+          tokens: [
+            {
+              type: "text",
+              raw: text,
+              text
+            }
+          ]
         };
-      },
-      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]);
+      }
+    }
+    inlineText(src) {
+      const cap = this.rules.inline.text.exec(src);
+      if (cap) {
+        let text;
+        if (this.lexer.state.inRawBlock) {
+          text = cap[0];
+        } else {
+          text = escape$1(cap[0]);
+        }
+        return {
+          type: "text",
+          raw: cap[0],
+          text
         };
       }
-    };
+    }
   };
-  var buildLineKeys = function() {
-    return {
-      highway: {
-        rest_area: true,
-        services: true
-      },
-      railway: {
-        roundhouse: true,
-        station: true,
-        traverser: true,
-        turntable: true,
-        wash: true
-      }
-    };
+  var newline = /^(?: *(?:\n|$))+/;
+  var blockCode = /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/;
+  var fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/;
+  var hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
+  var heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
+  var bullet = /(?:[*+-]|\d{1,9}[.)])/;
+  var lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g, bullet).replace(/blockCode/g, / {4}/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).getRegex();
+  var _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
+  var blockText = /^[^\n]+/;
+  var _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
+  var def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label", _blockLabel).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
+  var list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, bullet).getRegex();
+  var _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|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
+  var _comment = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
+  var html2 = edit("^ {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|$))", "i").replace("comment", _comment).replace("tag", _tag).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
+  var paragraph = edit(_paragraph).replace("hr", hr).replace("heading", " {0,3}#{1,6}(?:\\s|$)").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", _tag).getRegex();
+  var blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", paragraph).getRegex();
+  var blockNormal = {
+    blockquote,
+    code: blockCode,
+    def,
+    fences,
+    heading,
+    hr,
+    html: html2,
+    lheading,
+    list,
+    newline,
+    paragraph,
+    table: noopTest,
+    text: blockText
   };
-  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]));
+  var gfmTable = edit("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", hr).replace("heading", " {0,3}#{1,6}(?:\\s|$)").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", _tag).getRegex();
+  var blockGfm = {
+    ...blockNormal,
+    table: gfmTable,
+    paragraph: edit(_paragraph).replace("hr", hr).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", gfmTable).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", _tag).getRegex()
+  };
+  var blockPedantic = {
+    ...blockNormal,
+    html: edit("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment", _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(_paragraph).replace("hr", hr).replace("heading", " *#{1,6} *[^\n]").replace("lheading", lheading).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex()
+  };
+  var escape4 = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
+  var inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
+  var br = /^( {2,}|\\)\n(?!\s*$)/;
+  var inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
+  var _punctuation = "\\p{P}\\p{S}";
+  var punctuation = edit(/^((?![*_])[\spunctuation])/, "u").replace(/punctuation/g, _punctuation).getRegex();
+  var blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
+  var emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, "u").replace(/punct/g, _punctuation).getRegex();
+  var emStrongRDelimAst = edit("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])", "gu").replace(/punct/g, _punctuation).getRegex();
+  var emStrongRDelimUnd = edit("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])", "gu").replace(/punct/g, _punctuation).getRegex();
+  var anyPunctuation = edit(/\\([punct])/, "gu").replace(/punct/g, _punctuation).getRegex();
+  var autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("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])?)+(?![-_])/).getRegex();
+  var _inlineComment = edit(_comment).replace("(?:-->|$)", "-->").getRegex();
+  var tag = edit("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", _inlineComment).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
+  var _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
+  var link2 = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label", _inlineLabel).replace("href", /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
+  var reflink = edit(/^!?\[(label)\]\[(ref)\]/).replace("label", _inlineLabel).replace("ref", _blockLabel).getRegex();
+  var nolink = edit(/^!?\[(ref)\](?:\[\])?/).replace("ref", _blockLabel).getRegex();
+  var reflinkSearch = edit("reflink|nolink(?!\\()", "g").replace("reflink", reflink).replace("nolink", nolink).getRegex();
+  var inlineNormal = {
+    _backpedal: noopTest,
+    // only used for GFM url
+    anyPunctuation,
+    autolink,
+    blockSkip,
+    br,
+    code: inlineCode,
+    del: noopTest,
+    emStrongLDelim,
+    emStrongRDelimAst,
+    emStrongRDelimUnd,
+    escape: escape4,
+    link: link2,
+    nolink,
+    punctuation,
+    reflink,
+    reflinkSearch,
+    tag,
+    text: inlineText,
+    url: noopTest
+  };
+  var inlinePedantic = {
+    ...inlineNormal,
+    link: edit(/^!?\[(label)\]\((.*?)\)/).replace("label", _inlineLabel).getRegex(),
+    reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", _inlineLabel).getRegex()
+  };
+  var inlineGfm = {
+    ...inlineNormal,
+    escape: edit(escape4).replace("])", "~|])").getRegex(),
+    url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, "i").replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),
+    _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.!#$%&'*+\/=?_`{\|}~-]+@)))/
+  };
+  var inlineBreaks = {
+    ...inlineGfm,
+    br: edit(br).replace("{2,}", "*").getRegex(),
+    text: edit(inlineGfm.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex()
+  };
+  var block = {
+    normal: blockNormal,
+    gfm: blockGfm,
+    pedantic: blockPedantic
+  };
+  var inline = {
+    normal: inlineNormal,
+    gfm: inlineGfm,
+    breaks: inlineBreaks,
+    pedantic: inlinePedantic
+  };
+  var _Lexer = class __Lexer {
+    constructor(options2) {
+      __publicField(this, "tokens");
+      __publicField(this, "options");
+      __publicField(this, "state");
+      __publicField(this, "tokenizer");
+      __publicField(this, "inlineQueue");
+      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;
         }
-        return rules;
-      }, []);
-    },
-    buildTagMap: function(selector) {
-      var getRegexValues = function(regexes) {
-        return regexes.map(function(regex) {
-          return regex.replace(/\$|\^/g, "");
-        });
+      }
+      this.tokenizer.rules = rules;
+    }
+    /**
+     * Expose Rules
+     */
+    static get rules() {
+      return {
+        block,
+        inline
       };
-      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]);
+    }
+    /**
+     * 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);
+      for (let i3 = 0; i3 < this.inlineQueue.length; i3++) {
+        const next = this.inlineQueue[i3];
+        this.inlineTokens(next.src, next.tokens);
+      }
+      this.inlineQueue = [];
+      return this.tokens;
+    }
+    blockTokens(src, tokens = [], lastParagraphClipped = false) {
+      if (this.options.pedantic) {
+        src = src.replace(/\t/g, "    ").replace(/^ +$/gm, "");
+      } else {
+        src = src.replace(/^( *)(\t+)/gm, (_2, leading, tabs) => {
+          return leading + "    ".repeat(tabs.length);
+        });
+      }
+      let token;
+      let lastToken;
+      let cutSrc;
+      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;
           }
-          expectedTags[tagKey] = values;
+          return false;
+        })) {
+          continue;
         }
-        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";
+        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 (tagMap.area.indexOf("no") > -1) {
-          return "line";
+        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;
         }
-      }
-      for (var key in tagMap) {
-        if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
-          return "area";
+        if (token = this.tokenizer.fences(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        if (key in _lineKeys && keyValueImpliesLine(key)) {
-          return "area";
+        if (token = this.tokenizer.heading(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.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;
         }
-      };
-      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.table(src)) {
+          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.lheading(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);
+        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((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 (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+)$"
-        }
-      },
-      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 (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
+          lastToken = tokens[tokens.length - 1];
+          if (lastParagraphClipped && (lastToken == null ? void 0 : 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;
         }
-      },
-      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 (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;
         }
-      },
-      transit: {
-        emoji: "\u{1F687}",
-        mainTag: "network:wikidata",
-        sourceTags: ["network"],
-        nameTags: {
-          primary: "^network$",
-          alternate: "^(operator|operator:\\w+|network:\\w+|\\w+_name|\\w+_name:\\w+)$"
+        if (src) {
+          const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
+          if (this.options.silent) {
+            console.error(errMsg);
+            break;
+          } else {
+            throw new Error(errMsg);
+          }
         }
       }
+      this.state.top = true;
+      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 = [];
+    inline(src, tokens = []) {
+      this.inlineQueue.push({ src, tokens });
+      return tokens;
     }
-    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));
+    /**
+     * 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);
             }
-          });
-          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);
         }
       }
-      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";
+      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);
       }
-    }
-    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));
-      }
-    }
-    match(k, v, n2, loc) {
-      const that = this;
-      if (!that.matchIndex) {
-        throw new Error("match:  matchIndex not built.");
-      }
-      let matchLocations;
-      if (Array.isArray(loc) && that.locationIndex) {
-        matchLocations = that.locationIndex([loc[0], loc[1], loc[0], loc[1]], true);
+      while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
+        maskedSrc = maskedSrc.slice(0, match.index) + "++" + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
       }
-      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;
-          }
+      while (src) {
+        if (!keepPrevChar) {
+          prevChar = "";
         }
-        if (which === "exclude") {
-          const regex = [...that.genericWords.values()].find((regex2) => regex2.test(n2));
-          if (regex) {
-            results.push({ match: "excludeGeneric", pattern: String(regex) });
-            return;
+        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;
         }
-      }
-      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;
+        if (token = this.tokenizer.escape(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        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;
+        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);
           }
-          return { match: which, itemID, area, kv, nsimple };
-        });
-        let sortFn = byAreaDescending;
-        if (matchLocations) {
-          hits = hits.filter(isValidLocation);
-          sortFn = byAreaAscending;
+          continue;
         }
-        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));
+        if (token = this.tokenizer.link(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        function byAreaAscending(hitA, hitB) {
-          return hitA.area - hitB.area;
+        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;
         }
-        function byAreaDescending(hitA, hitB) {
-          return hitB.area - hitA.area;
+        if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      }
-    }
-    getWarnings() {
-      return this.warnings;
-    }
-  };
-
-  // 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;
-      }
-      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 (token = this.tokenizer.codespan(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
-          _changes[id2] = { base: b, head: h };
-          _didChange.geometry = true;
+        if (token = this.tokenizer.br(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        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 (token = this.tokenizer.del(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-        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 (token = this.tokenizer.autolink(src)) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          continue;
         }
-      }
-    }
-    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);
+        if (!this.state.inLink && (token = this.tokenizer.url(src))) {
+          src = src.substring(token.raw.length);
+          tokens.push(token);
+          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);
+        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((getStartIndex) => {
+            tempStart = getStartIndex.call({ lexer: this }, tempSrc);
+            if (typeof tempStart === "number" && tempStart >= 0) {
+              startIndex = Math.min(startIndex, tempStart);
             }
           });
-        }
-      });
-      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);
-          }
-          if (retagged || moved && change.head.hasInterestingTags()) {
-            addEntity(change.head, head, "modified");
+          if (startIndex < Infinity && startIndex >= 0) {
+            cutSrc = src.substring(0, startIndex + 1);
           }
-        } 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");
+        if (token = this.tokenizer.inlineText(cutSrc)) {
+          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);
           }
-        }
-      }
-    };
-    _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 (src) {
+          const errMsg = "Infinite loop on byte: " + src.charCodeAt(0);
+          if (this.options.silent) {
+            console.error(errMsg);
+            break;
+          } else {
+            throw new Error(errMsg);
           }
         }
-        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;
+      }
+      return tokens;
+    }
+  };
+  var _Renderer = class {
+    // set by the parser
+    constructor(options2) {
+      __publicField(this, "options");
+      __publicField(this, "parser");
+      this.options = options2 || _defaults;
+    }
+    space(token) {
+      return "";
+    }
+    code({ text, lang, escaped }) {
+      var _a3;
+      const langString = (_a3 = (lang || "").match(/^\S*/)) == null ? void 0 : _a3[0];
+      const code = text.replace(/\n$/, "") + "\n";
+      if (!langString) {
+        return "<pre><code>" + (escaped ? code : escape$1(code, true)) + "</code></pre>\n";
+      }
+      return '<pre><code class="language-' + escape$1(langString) + '">' + (escaped ? code : escape$1(code, true)) + "</code></pre>\n";
+    }
+    blockquote({ tokens }) {
+      const body = this.parser.parse(tokens);
+      return "<blockquote>\n".concat(body, "</blockquote>\n");
+    }
+    html({ text }) {
+      return text;
+    }
+    heading({ tokens, depth }) {
+      return "<h".concat(depth, ">").concat(this.parser.parseInline(tokens), "</h").concat(depth, ">\n");
+    }
+    hr(token) {
+      return "<hr>\n";
+    }
+    list(token) {
+      const ordered = token.ordered;
+      const start2 = token.start;
+      let body = "";
+      for (let j2 = 0; j2 < token.items.length; j2++) {
+        const item = token.items[j2];
+        body += this.listitem(item);
+      }
+      const type2 = ordered ? "ol" : "ul";
+      const startAttr = ordered && start2 !== 1 ? ' start="' + start2 + '"' : "";
+      return "<" + type2 + startAttr + ">\n" + body + "</" + type2 + ">\n";
+    }
+    listitem(item) {
+      let itemBody = "";
+      if (item.task) {
+        const checkbox = this.checkbox({ checked: !!item.checked });
+        if (item.loose) {
+          if (item.tokens.length > 0 && item.tokens[0].type === "paragraph") {
+            item.tokens[0].text = checkbox + " " + item.tokens[0].text;
+            if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === "text") {
+              item.tokens[0].tokens[0].text = checkbox + " " + item.tokens[0].tokens[0].text;
+            }
+          } else {
+            item.tokens.unshift({
+              type: "text",
+              raw: checkbox + " ",
+              text: checkbox + " "
+            });
           }
+        } else {
+          itemBody += checkbox + " ";
         }
-        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);
+      itemBody += this.parser.parse(item.tokens, !!item.loose);
+      return "<li>".concat(itemBody, "</li>\n");
+    }
+    checkbox({ checked }) {
+      return "<input " + (checked ? 'checked="" ' : "") + 'disabled="" type="checkbox">';
+    }
+    paragraph({ tokens }) {
+      return "<p>".concat(this.parser.parseInline(tokens), "</p>\n");
+    }
+    table(token) {
+      let header = "";
+      let cell = "";
+      for (let j2 = 0; j2 < token.header.length; j2++) {
+        cell += this.tablecell(token.header[j2]);
+      }
+      header += this.tablerow({ text: cell });
+      let body = "";
+      for (let j2 = 0; j2 < token.rows.length; j2++) {
+        const row = token.rows[j2];
+        cell = "";
+        for (let k2 = 0; k2 < row.length; k2++) {
+          cell += this.tablecell(row[k2]);
         }
+        body += this.tablerow({ text: cell });
       }
-    };
-    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;
+      if (body)
+        body = "<tbody>".concat(body, "</tbody>");
+      return "<table>\n<thead>\n" + header + "</thead>\n" + body + "</table>\n";
     }
-    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;
+    tablerow({ text }) {
+      return "<tr>\n".concat(text, "</tr>\n");
     }
-    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];
-      }
+    tablecell(token) {
+      const content = this.parser.parseInline(token.tokens);
+      const type2 = token.header ? "th" : "td";
+      const tag2 = token.align ? "<".concat(type2, ' align="').concat(token.align, '">') : "<".concat(type2, ">");
+      return tag2 + content + "</".concat(type2, ">\n");
     }
-    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));
+    /**
+     * span level renderer
+     */
+    strong({ tokens }) {
+      return "<strong>".concat(this.parser.parseInline(tokens), "</strong>");
     }
-    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);
-      });
+    em({ tokens }) {
+      return "<em>".concat(this.parser.parseInline(tokens), "</em>");
     }
-    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, {});
+    codespan({ text }) {
+      return "<code>".concat(text, "</code>");
+    }
+    br(token) {
+      return "<br>";
+    }
+    del({ tokens }) {
+      return "<del>".concat(this.parser.parseInline(tokens), "</del>");
+    }
+    link({ href, title, tokens }) {
+      const text = this.parser.parseInline(tokens);
+      const cleanHref = cleanUrl(href);
+      if (cleanHref === null) {
+        return text;
       }
-      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);
-        });
+      href = cleanHref;
+      let out = '<a href="' + href + '"';
+      if (title) {
+        out += ' title="' + title + '"';
       }
-      if (changed.geometry) {
-        diff.modified().forEach(function(entity) {
-          removeEntity(entity);
-          insertions[entity.id] = entity;
-          updateParents(entity, insertions, {});
-        });
+      out += ">" + text + "</a>";
+      return out;
+    }
+    image({ href, title, text }) {
+      const cleanHref = cleanUrl(href);
+      if (cleanHref === null) {
+        return text;
       }
-      if (changed.addition) {
-        diff.created().forEach(function(entity) {
-          insertions[entity.id] = entity;
-        });
+      href = cleanHref;
+      let out = '<img src="'.concat(href, '" alt="').concat(text, '"');
+      if (title) {
+        out += ' title="'.concat(title, '"');
       }
-      loadEntities(Object.values(insertions));
+      out += ">";
+      return out;
     }
-    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);
-    };
-  }
-
-  // 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);
+    text(token) {
+      return "tokens" in token && token.tokens ? this.parser.parseInline(token.tokens) : token.text;
     }
-    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);
+  };
+  var _TextRenderer = class {
+    // no need for block level renderers
+    strong({ text }) {
+      return text;
     }
-    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();
-      }
+    em({ text }) {
+      return text;
     }
-    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();
-      }
+    codespan({ text }) {
+      return text;
     }
-  }
-
-  // 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()
-      };
+    del({ text }) {
+      return text;
     }
-    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);
+    html({ text }) {
+      return text;
     }
-    function _replace(args, t) {
-      var previous = _stack[_index].graph;
-      var actionResult = _act(args, t);
-      _stack[_index] = actionResult;
-      return change(previous);
+    text({ text }) {
+      return text;
     }
-    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);
+    link({ text }) {
+      return "" + text;
     }
-    function change(previous) {
-      var difference = coreDifference(previous, history.graph());
-      if (!_pausedGraph) {
-        dispatch10.call("change", this, difference);
-      }
-      return difference;
+    image({ text }) {
+      return "" + text;
     }
-    function getKey(n2) {
-      return "iD_" + window.location.origin + "_" + n2;
+    br() {
+      return "";
     }
-    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");
-        var transitionable = false;
-        var action0 = arguments[0];
-        if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== "function") {
-          transitionable = !!action0.transitionable;
-        }
-        if (transitionable) {
-          var origArguments = arguments;
-          select_default2(document).transition("history.perform").duration(duration).ease(linear2).tween("history.tween", function() {
-            return function(t) {
-              if (t < 1)
-                _overwrite([action0], t);
-            };
-          }).on("start", function() {
-            _perform([action0], 0);
-          }).on("end interrupt", function() {
-            _overwrite(origArguments, 1);
-          });
-        } else {
-          return _perform(arguments);
-        }
-      },
-      replace: function() {
-        select_default2(document).interrupt("history.perform");
-        return _replace(arguments, 1);
-      },
-      overwrite: function() {
-        select_default2(document).interrupt("history.perform");
-        return _overwrite(arguments, 1);
-      },
-      pop: function(n2) {
-        select_default2(document).interrupt("history.perform");
-        var previous = _stack[_index].graph;
-        if (isNaN(+n2) || +n2 < 0) {
-          n2 = 1;
-        }
-        while (n2-- > 0 && _index > 0) {
-          _index--;
-          _stack.pop();
-        }
-        return change(previous);
-      },
-      undo: function() {
-        select_default2(document).interrupt("history.perform");
-        var previousStack = _stack[_index];
-        var previous = previousStack.graph;
-        while (_index > 0) {
-          _index--;
-          if (_stack[_index].annotation)
-            break;
-        }
-        dispatch10.call("undone", this, _stack[_index], previousStack);
-        return change(previous);
-      },
-      redo: function() {
-        select_default2(document).interrupt("history.perform");
-        var previousStack = _stack[_index];
-        var previous = previousStack.graph;
-        var tryIndex = _index;
-        while (tryIndex < _stack.length - 1) {
-          tryIndex++;
-          if (_stack[tryIndex].annotation) {
-            _index = tryIndex;
-            dispatch10.call("redone", this, _stack[_index], previousStack);
-            break;
+  };
+  var _Parser = class __Parser {
+    constructor(options2) {
+      __publicField(this, "options");
+      __publicField(this, "renderer");
+      __publicField(this, "textRenderer");
+      this.options = options2 || _defaults;
+      this.options.renderer = this.options.renderer || new _Renderer();
+      this.renderer = this.options.renderer;
+      this.renderer.options = this.options;
+      this.renderer.parser = this;
+      this.textRenderer = new _TextRenderer();
+    }
+    /**
+     * 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 = "";
+      for (let i3 = 0; i3 < tokens.length; i3++) {
+        const anyToken = tokens[i3];
+        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) {
+          const genericToken = anyToken;
+          const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);
+          if (ret !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "paragraph", "text"].includes(genericToken.type)) {
+            out += ret || "";
+            continue;
           }
         }
-        return change(previous);
-      },
-      pauseChangeDispatch: function() {
-        if (!_pausedGraph) {
-          _pausedGraph = _stack[_index].graph;
-        }
-      },
-      resumeChangeDispatch: function() {
-        if (_pausedGraph) {
-          var previous = _pausedGraph;
-          _pausedGraph = null;
-          return change(previous);
-        }
-      },
-      undoAnnotation: function() {
-        var i2 = _index;
-        while (i2 >= 0) {
-          if (_stack[i2].annotation)
-            return _stack[i2].annotation;
-          i2--;
-        }
-      },
-      redoAnnotation: function() {
-        var i2 = _index + 1;
-        while (i2 <= _stack.length - 1) {
-          if (_stack[i2].annotation)
-            return _stack[i2].annotation;
-          i2++;
-        }
-      },
-      intersects: function(extent) {
-        return _tree.intersects(extent, _stack[_index].graph);
-      },
-      difference: function() {
-        var base = _stack[0].graph;
-        var head = _stack[_index].graph;
-        return coreDifference(base, head);
-      },
-      changes: function(action) {
-        var base = _stack[0].graph;
-        var head = _stack[_index].graph;
-        if (action) {
-          head = action(head);
-        }
-        var difference = coreDifference(base, head);
-        return {
-          modified: difference.modified(),
-          created: difference.created(),
-          deleted: difference.deleted()
-        };
-      },
-      hasChanges: function() {
-        return this.difference().length() > 0;
-      },
-      imageryUsed: function(sources) {
-        if (sources) {
-          _imageryUsed = sources;
-          return history;
-        } else {
-          var s = /* @__PURE__ */ new Set();
-          _stack.slice(1, _index + 1).forEach(function(state) {
-            state.imageryUsed.forEach(function(source) {
-              if (source !== "Custom") {
-                s.add(source);
-              }
-            });
-          });
-          return Array.from(s);
-        }
-      },
-      photoOverlaysUsed: function(sources) {
-        if (sources) {
-          _photoOverlaysUsed = sources;
-          return history;
-        } else {
-          var s = /* @__PURE__ */ new Set();
-          _stack.slice(1, _index + 1).forEach(function(state) {
-            if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
-              state.photoOverlaysUsed.forEach(function(photoOverlay) {
-                s.add(photoOverlay);
+        const token = anyToken;
+        switch (token.type) {
+          case "space": {
+            out += this.renderer.space(token);
+            continue;
+          }
+          case "hr": {
+            out += this.renderer.hr(token);
+            continue;
+          }
+          case "heading": {
+            out += this.renderer.heading(token);
+            continue;
+          }
+          case "code": {
+            out += this.renderer.code(token);
+            continue;
+          }
+          case "table": {
+            out += this.renderer.table(token);
+            continue;
+          }
+          case "blockquote": {
+            out += this.renderer.blockquote(token);
+            continue;
+          }
+          case "list": {
+            out += this.renderer.list(token);
+            continue;
+          }
+          case "html": {
+            out += this.renderer.html(token);
+            continue;
+          }
+          case "paragraph": {
+            out += this.renderer.paragraph(token);
+            continue;
+          }
+          case "text": {
+            let textToken = token;
+            let body = this.renderer.text(textToken);
+            while (i3 + 1 < tokens.length && tokens[i3 + 1].type === "text") {
+              textToken = tokens[++i3];
+              body += "\n" + this.renderer.text(textToken);
+            }
+            if (top) {
+              out += this.renderer.paragraph({
+                type: "paragraph",
+                raw: body,
+                text: body,
+                tokens: [{ type: "text", raw: body, text: body }]
               });
+            } else {
+              out += body;
             }
-          });
-          return Array.from(s);
+            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);
+            }
+          }
         }
-      },
-      checkpoint: function(key) {
-        _checkpoints[key] = {
-          stack: _stack,
-          index: _index
-        };
-        return history;
-      },
-      reset: function(key) {
-        if (key !== void 0 && _checkpoints.hasOwnProperty(key)) {
-          _stack = _checkpoints[key].stack;
-          _index = _checkpoints[key].index;
-        } else {
-          _stack = [{ graph: coreGraph() }];
-          _index = 0;
-          _tree = coreTree(_stack[0].graph);
-          _checkpoints = {};
+      }
+      return out;
+    }
+    /**
+     * Parse Inline Tokens
+     */
+    parseInline(tokens, renderer) {
+      renderer = renderer || this.renderer;
+      let out = "";
+      for (let i3 = 0; i3 < tokens.length; i3++) {
+        const anyToken = tokens[i3];
+        if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) {
+          const ret = this.options.extensions.renderers[anyToken.type].call({ parser: this }, anyToken);
+          if (ret !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(anyToken.type)) {
+            out += ret || "";
+            continue;
+          }
         }
-        dispatch10.call("reset");
-        dispatch10.call("change");
-        return history;
-      },
-      toIntroGraph: function() {
-        var nextID = { n: 0, r: 0, w: 0 };
-        var permIDs = {};
-        var graph = this.graph();
-        var baseEntities = {};
-        Object.values(graph.base().entities).forEach(function(entity) {
-          var copy2 = copyIntroEntity(entity);
-          baseEntities[copy2.id] = copy2;
-        });
-        Object.keys(graph.entities).forEach(function(id2) {
-          var entity = graph.entities[id2];
-          if (entity) {
-            var copy2 = copyIntroEntity(entity);
-            baseEntities[copy2.id] = copy2;
-          } else {
-            delete baseEntities[id2];
+        const token = anyToken;
+        switch (token.type) {
+          case "escape": {
+            out += renderer.text(token);
+            break;
           }
-        });
-        Object.values(baseEntities).forEach(function(entity) {
-          if (Array.isArray(entity.nodes)) {
-            entity.nodes = entity.nodes.map(function(node) {
-              return permIDs[node] || node;
-            });
+          case "html": {
+            out += renderer.html(token);
+            break;
           }
-          if (Array.isArray(entity.members)) {
-            entity.members = entity.members.map(function(member) {
-              member.id = permIDs[member.id] || member.id;
-              return member;
-            });
+          case "link": {
+            out += renderer.link(token);
+            break;
           }
-        });
-        return JSON.stringify({ dataIntroGraph: baseEntities });
-        function copyIntroEntity(source) {
-          var copy2 = utilObjectOmit(source, ["type", "user", "v", "version", "visible"]);
-          if (copy2.tags && !Object.keys(copy2.tags)) {
-            delete copy2.tags;
+          case "image": {
+            out += renderer.image(token);
+            break;
           }
-          if (Array.isArray(copy2.loc)) {
-            copy2.loc[0] = +copy2.loc[0].toFixed(6);
-            copy2.loc[1] = +copy2.loc[1].toFixed(6);
+          case "strong": {
+            out += renderer.strong(token);
+            break;
           }
-          var match = source.id.match(/([nrw])-\d*/);
-          if (match !== null) {
-            var nrw = match[1];
-            var permID;
-            do {
-              permID = nrw + ++nextID[nrw];
-            } while (baseEntities.hasOwnProperty(permID));
-            copy2.id = permIDs[source.id] = permID;
+          case "em": {
+            out += renderer.em(token);
+            break;
           }
-          return copy2;
-        }
-      },
-      toJSON: function() {
-        if (!this.hasChanges())
-          return;
-        var allEntities = {};
-        var baseEntities = {};
-        var base = _stack[0];
-        var s = _stack.map(function(i2) {
-          var modified = [];
-          var deleted = [];
-          Object.keys(i2.graph.entities).forEach(function(id2) {
-            var entity = i2.graph.entities[id2];
-            if (entity) {
-              var key = osmEntity.key(entity);
-              allEntities[key] = entity;
-              modified.push(key);
+          case "codespan": {
+            out += renderer.codespan(token);
+            break;
+          }
+          case "br": {
+            out += renderer.br(token);
+            break;
+          }
+          case "del": {
+            out += renderer.del(token);
+            break;
+          }
+          case "text": {
+            out += renderer.text(token);
+            break;
+          }
+          default: {
+            const errMsg = 'Token with "' + token.type + '" type was not found.';
+            if (this.options.silent) {
+              console.error(errMsg);
+              return "";
             } else {
-              deleted.push(id2);
+              throw new Error(errMsg);
             }
-            if (id2 in base.graph.entities) {
-              baseEntities[id2] = base.graph.entities[id2];
+          }
+        }
+      }
+      return out;
+    }
+  };
+  var _Hooks = class {
+    constructor(options2) {
+      __publicField(this, "options");
+      this.options = options2 || _defaults;
+    }
+    /**
+     * Process markdown before marked
+     */
+    preprocess(markdown) {
+      return markdown;
+    }
+    /**
+     * Process HTML after marked is finished
+     */
+    postprocess(html3) {
+      return html3;
+    }
+    /**
+     * Process all tokens before walk tokens
+     */
+    processAllTokens(tokens) {
+      return tokens;
+    }
+  };
+  __publicField(_Hooks, "passThroughHooks", /* @__PURE__ */ new Set([
+    "preprocess",
+    "postprocess",
+    "processAllTokens"
+  ]));
+  var Marked = class {
+    constructor(...args) {
+      __publicField(this, "defaults", _getDefaults());
+      __publicField(this, "options", this.setOptions);
+      __publicField(this, "parse", this.parseMarkdown(_Lexer.lex, _Parser.parse));
+      __publicField(this, "parseInline", this.parseMarkdown(_Lexer.lexInline, _Parser.parseInline));
+      __publicField(this, "Parser", _Parser);
+      __publicField(this, "Renderer", _Renderer);
+      __publicField(this, "TextRenderer", _TextRenderer);
+      __publicField(this, "Lexer", _Lexer);
+      __publicField(this, "Tokenizer", _Tokenizer);
+      __publicField(this, "Hooks", _Hooks);
+      this.use(...args);
+    }
+    /**
+     * Run callback for every token
+     */
+    walkTokens(tokens, callback) {
+      var _a3, _b3;
+      let values = [];
+      for (const token of tokens) {
+        values = values.concat(callback.call(this, token));
+        switch (token.type) {
+          case "table": {
+            const tableToken = token;
+            for (const cell of tableToken.header) {
+              values = values.concat(this.walkTokens(cell.tokens, callback));
             }
-            if (entity && entity.nodes) {
-              entity.nodes.forEach(function(nodeID) {
-                if (nodeID in base.graph.entities) {
-                  baseEntities[nodeID] = base.graph.entities[nodeID];
-                }
-              });
+            for (const row of tableToken.rows) {
+              for (const cell of row) {
+                values = values.concat(this.walkTokens(cell.tokens, callback));
+              }
             }
-            var baseParents = base.graph._parentWays[id2];
-            if (baseParents) {
-              baseParents.forEach(function(parentID) {
-                if (parentID in base.graph.entities) {
-                  baseEntities[parentID] = base.graph.entities[parentID];
-                }
+            break;
+          }
+          case "list": {
+            const listToken = token;
+            values = values.concat(this.walkTokens(listToken.items, callback));
+            break;
+          }
+          default: {
+            const genericToken = token;
+            if ((_b3 = (_a3 = this.defaults.extensions) == null ? void 0 : _a3.childTokens) == null ? void 0 : _b3[genericToken.type]) {
+              this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {
+                const tokens2 = genericToken[childTokens].flat(Infinity);
+                values = values.concat(this.walkTokens(tokens2, callback));
               });
+            } else if (genericToken.tokens) {
+              values = values.concat(this.walkTokens(genericToken.tokens, callback));
             }
-          });
-          var x = {};
-          if (modified.length)
-            x.modified = modified;
-          if (deleted.length)
-            x.deleted = deleted;
-          if (i2.imageryUsed)
-            x.imageryUsed = i2.imageryUsed;
-          if (i2.photoOverlaysUsed)
-            x.photoOverlaysUsed = i2.photoOverlaysUsed;
-          if (i2.annotation)
-            x.annotation = i2.annotation;
-          if (i2.transform)
-            x.transform = i2.transform;
-          if (i2.selectedIDs)
-            x.selectedIDs = i2.selectedIDs;
-          return x;
-        });
-        return JSON.stringify({
-          version: 3,
-          entities: Object.values(allEntities),
-          baseEntities: Object.values(baseEntities),
-          stack: s,
-          nextIDs: osmEntity.id.next,
-          index: _index,
-          timestamp: new Date().getTime()
-        });
-      },
-      fromJSON: function(json, loadChildNodes) {
-        var h = JSON.parse(json);
-        var loadComplete = true;
-        osmEntity.id.next = h.nextIDs;
-        _index = h.index;
-        if (h.version === 2 || h.version === 3) {
-          var allEntities = {};
-          h.entities.forEach(function(entity) {
-            allEntities[osmEntity.key(entity)] = osmEntity(entity);
-          });
-          if (h.version === 3) {
-            var baseEntities = h.baseEntities.map(function(d) {
-              return osmEntity(d);
-            });
-            var stack = _stack.map(function(state) {
-              return state.graph;
-            });
-            _stack[0].graph.rebase(baseEntities, stack, true);
-            _tree.rebase(baseEntities, true);
-            if (loadChildNodes) {
-              var osm = context.connection();
-              var baseWays = baseEntities.filter(function(e) {
-                return e.type === "way";
-              });
-              var nodeIDs = baseWays.reduce(function(acc, way) {
-                return utilArrayUnion(acc, way.nodes);
-              }, []);
-              var missing = nodeIDs.filter(function(n2) {
-                return !_stack[0].graph.hasEntity(n2);
-              });
-              if (missing.length && osm) {
-                loadComplete = false;
-                context.map().redrawEnable(false);
-                var loading = uiLoading(context).blocking(true);
-                context.container().call(loading);
-                var childNodesLoaded = function(err, result) {
-                  if (!err) {
-                    var visibleGroups = utilArrayGroupBy(result.data, "visible");
-                    var visibles = visibleGroups.true || [];
-                    var invisibles = visibleGroups.false || [];
-                    if (visibles.length) {
-                      var visibleIDs = visibles.map(function(entity) {
-                        return entity.id;
-                      });
-                      var stack2 = _stack.map(function(state) {
-                        return state.graph;
-                      });
-                      missing = utilArrayDifference(missing, visibleIDs);
-                      _stack[0].graph.rebase(visibles, stack2, true);
-                      _tree.rebase(visibles, true);
-                    }
-                    invisibles.forEach(function(entity) {
-                      osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
-                    });
-                  }
-                  if (err || !missing.length) {
-                    loading.close();
-                    context.map().redrawEnable(true);
-                    dispatch10.call("change");
-                    dispatch10.call("restore", this);
+          }
+        }
+      }
+      return values;
+    }
+    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 ("renderer" in ext) {
+              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;
                 };
-                osm.loadMultiple(missing, childNodesLoaded);
+              } else {
+                extensions.renderers[ext.name] = ext.renderer;
               }
             }
-          }
-          _stack = h.stack.map(function(d) {
-            var entities = {}, entity;
-            if (d.modified) {
-              d.modified.forEach(function(key) {
-                entity = allEntities[key];
-                entities[entity.id] = entity;
-              });
-            }
-            if (d.deleted) {
-              d.deleted.forEach(function(id2) {
-                entities[id2] = void 0;
-              });
+            if ("tokenizer" in ext) {
+              if (!ext.level || ext.level !== "block" && ext.level !== "inline") {
+                throw new Error("extension level must be 'block' or 'inline'");
+              }
+              const extLevel = extensions[ext.level];
+              if (extLevel) {
+                extLevel.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];
+                  }
+                }
+              }
             }
-            return {
-              graph: coreGraph(_stack[0].graph).load(entities),
-              annotation: d.annotation,
-              imageryUsed: d.imageryUsed,
-              photoOverlaysUsed: d.photoOverlaysUsed,
-              transform: d.transform,
-              selectedIDs: d.selectedIDs
-            };
-          });
-        } else {
-          _stack = h.stack.map(function(d) {
-            var entities = {};
-            for (var i2 in d.entities) {
-              var entity = d.entities[i2];
-              entities[i2] = entity === "undefined" ? void 0 : osmEntity(entity);
+            if ("childTokens" in ext && ext.childTokens) {
+              extensions.childTokens[ext.name] = ext.childTokens;
             }
-            d.graph = coreGraph(_stack[0].graph).load(entities);
-            return d;
           });
+          opts.extensions = extensions;
         }
-        var transform2 = _stack[_index].transform;
-        if (transform2) {
-          context.map().transformEase(transform2, 0);
-        }
-        if (loadComplete) {
-          dispatch10.call("change");
-          dispatch10.call("restore", this);
+        if (pack.renderer) {
+          const renderer = this.defaults.renderer || new _Renderer(this.defaults);
+          for (const prop in pack.renderer) {
+            if (!(prop in renderer)) {
+              throw new Error("renderer '".concat(prop, "' does not exist"));
+            }
+            if (["options", "parser"].includes(prop)) {
+              continue;
+            }
+            const rendererProp = prop;
+            const rendererFunc = pack.renderer[rendererProp];
+            const prevRenderer = renderer[rendererProp];
+            renderer[rendererProp] = (...args2) => {
+              let ret = rendererFunc.apply(renderer, args2);
+              if (ret === false) {
+                ret = prevRenderer.apply(renderer, args2);
+              }
+              return ret || "";
+            };
+          }
+          opts.renderer = renderer;
         }
-        return history;
-      },
-      lock: function() {
-        return lock.lock();
-      },
-      unlock: function() {
-        lock.unlock();
-      },
-      save: function() {
-        if (lock.locked() && !_hasUnresolvedRestorableChanges) {
-          const success = corePreferences(getKey("saved_history"), history.toJSON() || null);
-          if (!success)
-            dispatch10.call("storage_error");
-        }
-        return history;
-      },
-      clearSaved: function() {
-        context.debouncedSave.cancel();
-        if (lock.locked()) {
-          _hasUnresolvedRestorableChanges = false;
-          corePreferences(getKey("saved_history"), null);
-          corePreferences("comment", null);
-          corePreferences("hashtags", null);
-          corePreferences("source", null);
-        }
-        return history;
-      },
-      savedHistoryJSON: function() {
-        return corePreferences(getKey("saved_history"));
-      },
-      hasRestorableChanges: function() {
-        return _hasUnresolvedRestorableChanges;
-      },
-      restore: function() {
-        if (lock.locked()) {
-          _hasUnresolvedRestorableChanges = false;
-          var json = this.savedHistoryJSON();
-          if (json)
-            history.fromJSON(json, true);
-        }
-      },
-      _getKey: getKey
-    };
-    history.reset();
-    return utilRebind(history, dispatch10, "on");
-  }
-
-  // modules/validations/index.js
-  var validations_exports = {};
-  __export(validations_exports, {
-    validationAlmostJunction: () => validationAlmostJunction,
-    validationCloseNodes: () => validationCloseNodes,
-    validationCrossingWays: () => validationCrossingWays,
-    validationDisconnectedWay: () => validationDisconnectedWay,
-    validationFormatting: () => validationFormatting,
-    validationHelpRequest: () => validationHelpRequest,
-    validationImpossibleOneway: () => validationImpossibleOneway,
-    validationIncompatibleSource: () => validationIncompatibleSource,
-    validationMaprules: () => validationMaprules,
-    validationMismatchedGeometry: () => validationMismatchedGeometry,
-    validationMissingRole: () => validationMissingRole,
-    validationMissingTag: () => validationMissingTag,
-    validationOutdatedTags: () => validationOutdatedTags,
-    validationPrivateData: () => validationPrivateData,
-    validationSuspiciousName: () => validationSuspiciousName,
-    validationUnsquareWay: () => validationUnsquareWay
-  });
-
-  // modules/validations/almost_junction.js
-  function validationAlmostJunction(context) {
-    const type3 = "almost_junction";
-    const EXTEND_TH_METERS = 5;
-    const WELD_TH_METERS = 0.75;
-    const CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS;
-    const SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
-    function isHighway(entity) {
-      return entity.type === "way" && osmRoutableHighwayTagValues[entity.tags.highway];
-    }
-    function isTaggedAsNotContinuing(node) {
-      return node.tags.noexit === "yes" || node.tags.amenity === "parking_entrance" || node.tags.entrance && node.tags.entrance !== "no";
-    }
-    const validation = function checkAlmostJunction(entity, graph) {
-      if (!isHighway(entity))
-        return [];
-      if (entity.isDegenerate())
-        return [];
-      const tree = context.history().tree();
-      const extendableNodeInfos = findConnectableEndNodesByExtension(entity);
-      let issues = [];
-      extendableNodeInfos.forEach((extendableNodeInfo) => {
-        issues.push(new validationIssue({
-          type: type3,
-          subtype: "highway-highway",
-          severity: "warning",
-          message: function(context2) {
-            const entity1 = context2.hasEntity(this.entityIds[0]);
-            if (this.entityIds[0] === this.entityIds[2]) {
-              return entity1 ? _t.append("issues.almost_junction.self.message", {
-                feature: utilDisplayLabel(entity1, context2.graph())
-              }) : "";
-            } else {
-              const entity2 = context2.hasEntity(this.entityIds[2]);
-              return entity1 && entity2 ? _t.append("issues.almost_junction.message", {
-                feature: utilDisplayLabel(entity1, context2.graph()),
-                feature2: utilDisplayLabel(entity2, context2.graph())
-              }) : "";
+        if (pack.tokenizer) {
+          const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults);
+          for (const prop in pack.tokenizer) {
+            if (!(prop in tokenizer)) {
+              throw new Error("tokenizer '".concat(prop, "' does not exist"));
             }
-          },
-          reference: showReference,
-          entityIds: [
-            entity.id,
-            extendableNodeInfo.node.id,
-            extendableNodeInfo.wid
-          ],
-          loc: extendableNodeInfo.node.loc,
-          hash: JSON.stringify(extendableNodeInfo.node.loc),
-          data: {
-            midId: extendableNodeInfo.mid.id,
-            edge: extendableNodeInfo.edge,
-            cross_loc: extendableNodeInfo.cross_loc
-          },
-          dynamicFixes: makeFixes
-        }));
-      });
-      return issues;
-      function makeFixes(context2) {
-        let fixes = [new validationIssueFix({
-          icon: "iD-icon-abutment",
-          title: _t.append("issues.fix.connect_features.title"),
-          onClick: function(context3) {
-            const annotation = _t("issues.fix.connect_almost_junction.annotation");
-            const [, endNodeId, crossWayId] = this.issue.entityIds;
-            const midNode = context3.entity(this.issue.data.midId);
-            const endNode = context3.entity(endNodeId);
-            const crossWay = context3.entity(crossWayId);
-            const nearEndNodes = findNearbyEndNodes(endNode, crossWay);
-            if (nearEndNodes.length > 0) {
-              const collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
-              if (collinear) {
-                context3.perform(
-                  actionMergeNodes([collinear.id, endNode.id], collinear.loc),
-                  annotation
-                );
-                return;
+            if (["options", "rules", "lexer"].includes(prop)) {
+              continue;
+            }
+            const tokenizerProp = prop;
+            const tokenizerFunc = pack.tokenizer[tokenizerProp];
+            const prevTokenizer = tokenizer[tokenizerProp];
+            tokenizer[tokenizerProp] = (...args2) => {
+              let ret = tokenizerFunc.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) {
+            if (!(prop in hooks)) {
+              throw new Error("hook '".concat(prop, "' does not exist"));
             }
-            const targetEdge = this.issue.data.edge;
-            const crossLoc = this.issue.data.cross_loc;
-            const edgeNodes = [context3.entity(targetEdge[0]), context3.entity(targetEdge[1])];
-            const closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc);
-            if (closestNodeInfo.distance < WELD_TH_METERS) {
-              context3.perform(
-                actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc),
-                annotation
-              );
+            if (prop === "options") {
+              continue;
+            }
+            const hooksProp = prop;
+            const hooksFunc = pack.hooks[hooksProp];
+            const prevHook = hooks[hooksProp];
+            if (_Hooks.passThroughHooks.has(prop)) {
+              hooks[hooksProp] = (arg) => {
+                if (this.defaults.async) {
+                  return Promise.resolve(hooksFunc.call(hooks, arg)).then((ret2) => {
+                    return prevHook.call(hooks, ret2);
+                  });
+                }
+                const ret = hooksFunc.call(hooks, arg);
+                return prevHook.call(hooks, ret);
+              };
             } else {
-              context3.perform(
-                actionAddMidpoint({ loc: crossLoc, edge: targetEdge }, endNode),
-                annotation
-              );
+              hooks[hooksProp] = (...args2) => {
+                let ret = hooksFunc.apply(hooks, args2);
+                if (ret === false) {
+                  ret = prevHook.apply(hooks, args2);
+                }
+                return ret;
+              };
             }
           }
-        })];
-        const node = context2.hasEntity(this.entityIds[1]);
-        if (node && !node.hasInterestingTags()) {
-          fixes.push(new validationIssueFix({
-            icon: "maki-barrier",
-            title: _t.append("issues.fix.tag_as_disconnected.title"),
-            onClick: function(context3) {
-              const nodeID = this.issue.entityIds[1];
-              const tags = Object.assign({}, context3.entity(nodeID).tags);
-              tags.noexit = "yes";
-              context3.perform(
-                actionChangeTags(nodeID, tags),
-                _t("issues.fix.tag_as_disconnected.annotation")
-              );
+          opts.hooks = hooks;
+        }
+        if (pack.walkTokens) {
+          const walkTokens2 = this.defaults.walkTokens;
+          const packWalktokens = pack.walkTokens;
+          opts.walkTokens = function(token) {
+            let values = [];
+            values.push(packWalktokens.call(this, token));
+            if (walkTokens2) {
+              values = values.concat(walkTokens2.call(this, token));
             }
-          }));
+            return values;
+          };
         }
-        return fixes;
-      }
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.almost_junction.highway-highway.reference"));
-      }
-      function isExtendableCandidate(node, way) {
-        const osm = services.osm;
-        if (osm && !osm.isDataLoaded(node.loc)) {
-          return false;
+        this.defaults = { ...this.defaults, ...opts };
+      });
+      return this;
+    }
+    setOptions(opt) {
+      this.defaults = { ...this.defaults, ...opt };
+      return this;
+    }
+    lexer(src, options2) {
+      return _Lexer.lex(src, options2 != null ? options2 : this.defaults);
+    }
+    parser(tokens, options2) {
+      return _Parser.parse(tokens, options2 != null ? options2 : this.defaults);
+    }
+    parseMarkdown(lexer2, parser3) {
+      const parse = (src, options2) => {
+        const origOpt = { ...options2 };
+        const opt = { ...this.defaults, ...origOpt };
+        const throwError = this.onError(!!opt.silent, !!opt.async);
+        if (this.defaults.async === true && origOpt.async === false) {
+          return throwError(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
         }
-        if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
-          return false;
+        if (typeof src === "undefined" || src === null) {
+          return throwError(new Error("marked(): input parameter is undefined or null"));
         }
-        let occurrences = 0;
-        for (const index in way.nodes) {
-          if (way.nodes[index] === node.id) {
-            occurrences += 1;
-            if (occurrences > 1) {
-              return false;
-            }
+        if (typeof src !== "string") {
+          return throwError(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(src) + ", string expected"));
+        }
+        if (opt.hooks) {
+          opt.hooks.options = opt;
+        }
+        if (opt.async) {
+          return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src).then((src2) => lexer2(src2, opt)).then((tokens) => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens).then((tokens) => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens).then((tokens) => parser3(tokens, opt)).then((html3) => opt.hooks ? opt.hooks.postprocess(html3) : html3).catch(throwError);
+        }
+        try {
+          if (opt.hooks) {
+            src = opt.hooks.preprocess(src);
           }
+          let tokens = lexer2(src, opt);
+          if (opt.hooks) {
+            tokens = opt.hooks.processAllTokens(tokens);
+          }
+          if (opt.walkTokens) {
+            this.walkTokens(tokens, opt.walkTokens);
+          }
+          let html3 = parser3(tokens, opt);
+          if (opt.hooks) {
+            html3 = opt.hooks.postprocess(html3);
+          }
+          return html3;
+        } catch (e3) {
+          return throwError(e3);
         }
-        return true;
+      };
+      return parse;
+    }
+    onError(silent, async) {
+      return (e3) => {
+        e3.message += "\nPlease report this to https://github.com/markedjs/marked.";
+        if (silent) {
+          const msg = "<p>An error occurred:</p><pre>" + escape$1(e3.message + "", true) + "</pre>";
+          if (async) {
+            return Promise.resolve(msg);
+          }
+          return msg;
+        }
+        if (async) {
+          return Promise.reject(e3);
+        }
+        throw e3;
+      };
+    }
+  };
+  var markedInstance = new Marked();
+  function marked(src, opt) {
+    return markedInstance.parse(src, opt);
+  }
+  marked.options = marked.setOptions = function(options2) {
+    markedInstance.setOptions(options2);
+    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.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 tiler2 = utilTiler();
+  var dispatch3 = dispatch_default("loaded");
+  var _tileZoom2 = 14;
+  var _osmoseUrlRoot = "https://osmose.openstreetmap.fr/api/0.3";
+  var _osmoseData = { icons: {}, items: [] };
+  var _cache2;
+  function abortRequest2(controller) {
+    if (controller) {
+      controller.abort();
+    }
+  }
+  function abortUnwantedRequests2(cache, tiles) {
+    Object.keys(cache.inflightTile).forEach((k2) => {
+      let wanted = tiles.find((tile) => k2 === tile.id);
+      if (!wanted) {
+        abortRequest2(cache.inflightTile[k2]);
+        delete cache.inflightTile[k2];
       }
-      function findConnectableEndNodesByExtension(way) {
-        let results = [];
-        if (way.isClosed())
-          return results;
-        let testNodes;
-        const indices = [0, way.nodes.length - 1];
-        indices.forEach((nodeIndex) => {
-          const nodeID = way.nodes[nodeIndex];
-          const node = graph.entity(nodeID);
-          if (!isExtendableCandidate(node, way))
-            return;
-          const connectionInfo = canConnectByExtend(way, nodeIndex);
-          if (!connectionInfo)
-            return;
-          testNodes = graph.childNodes(way).slice();
-          testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc);
-          if (geoHasSelfIntersections(testNodes, nodeID))
-            return;
-          results.push(connectionInfo);
-        });
-        return results;
+    });
+  }
+  function encodeIssueRtree2(d2) {
+    return { minX: d2.loc[0], minY: d2.loc[1], maxX: d2.loc[0], maxY: d2.loc[1], data: d2 };
+  }
+  function updateRtree2(item, replace) {
+    _cache2.rtree.remove(item, (a2, b2) => a2.data.id === b2.data.id);
+    if (replace) {
+      _cache2.rtree.insert(item);
+    }
+  }
+  function preventCoincident(loc) {
+    let coincident = false;
+    do {
+      let delta = coincident ? [1e-5, 0] : [0, 1e-5];
+      loc = geoVecAdd(loc, delta);
+      let bbox2 = geoExtent(loc).bbox();
+      coincident = _cache2.rtree.search(bbox2).length;
+    } while (coincident);
+    return loc;
+  }
+  var osmose_default = {
+    title: "osmose",
+    init() {
+      _mainFileFetcher.get("qa_data").then((d2) => {
+        _osmoseData = d2.osmose;
+        _osmoseData.items = Object.keys(d2.osmose.icons).map((s2) => s2.split("-")[0]).reduce((unique, item) => unique.indexOf(item) !== -1 ? unique : [...unique, item], []);
+      });
+      if (!_cache2) {
+        this.reset();
       }
-      function findNearbyEndNodes(node, way) {
-        return [
-          way.nodes[0],
-          way.nodes[way.nodes.length - 1]
-        ].map((d) => graph.entity(d)).filter((d) => {
-          return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
-        });
+      this.event = utilRebind(this, dispatch3, "on");
+    },
+    reset() {
+      let _strings = {};
+      let _colors = {};
+      if (_cache2) {
+        Object.values(_cache2.inflightTile).forEach(abortRequest2);
+        _strings = _cache2.strings;
+        _colors = _cache2.colors;
       }
-      function findSmallJoinAngle(midNode, tipNode, endNodes) {
-        let joinTo;
-        let minAngle = Infinity;
-        endNodes.forEach((endNode) => {
-          const a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
-          const a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
-          const diff = Math.max(a1, a2) - Math.min(a1, a2);
-          if (diff < minAngle) {
-            joinTo = endNode;
-            minAngle = diff;
+      _cache2 = {
+        data: {},
+        loadedTile: {},
+        inflightTile: {},
+        inflightPost: {},
+        closed: {},
+        rtree: new RBush(),
+        strings: _strings,
+        colors: _colors
+      };
+    },
+    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 = tiler2.zoomExtent([_tileZoom2, _tileZoom2]).getTiles(projection2);
+      abortUnwantedRequests2(_cache2, tiles);
+      tiles.forEach((tile) => {
+        if (_cache2.loadedTile[tile.id] || _cache2.inflightTile[tile.id]) return;
+        let [x2, y2, z2] = tile.xyz;
+        let url = "".concat(_osmoseUrlRoot, "/issues/").concat(z2, "/").concat(x2, "/").concat(y2, ".geojson?") + utilQsString(params);
+        let controller = new AbortController();
+        _cache2.inflightTile[tile.id] = controller;
+        json_default(url, { signal: controller.signal }).then((data) => {
+          delete _cache2.inflightTile[tile.id];
+          _cache2.loadedTile[tile.id] = true;
+          if (data.features) {
+            data.features.forEach((issue) => {
+              const { item, class: cl, uuid: id2 } = issue.properties;
+              const itemType = "".concat(item, "-").concat(cl);
+              if (itemType in _osmoseData.icons) {
+                let loc = issue.geometry.coordinates;
+                loc = preventCoincident(loc);
+                let d2 = new QAItem(loc, this, itemType, id2, { item });
+                if (item === 8300 || item === 8360) {
+                  d2.elems = [];
+                }
+                _cache2.data[d2.id] = d2;
+                _cache2.rtree.insert(encodeIssueRtree2(d2));
+              }
+            });
           }
+          dispatch3.call("loaded");
+        }).catch(() => {
+          delete _cache2.inflightTile[tile.id];
+          _cache2.loadedTile[tile.id] = true;
         });
-        if (minAngle <= SIG_ANGLE_TH)
-          return joinTo;
-        return null;
+      });
+    },
+    loadIssueDetail(issue) {
+      if (issue.elems !== void 0) {
+        return Promise.resolve(issue);
       }
-      function hasTag(tags, key) {
-        return tags[key] !== void 0 && tags[key] !== "no";
+      const url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
+      const cacheDetails = (data) => {
+        issue.elems = data.elems.map((e3) => e3.type.substring(0, 1) + e3.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 _cache2.strings && Object.keys(_cache2.strings[locale2]).length === items.length) {
+        return Promise.resolve(_cache2.strings[locale2]);
       }
-      function canConnectWays(way, way2) {
-        if (way.id === way2.id)
-          return true;
-        if ((hasTag(way.tags, "bridge") || hasTag(way2.tags, "bridge")) && !(hasTag(way.tags, "bridge") && hasTag(way2.tags, "bridge")))
-          return false;
-        if ((hasTag(way.tags, "tunnel") || hasTag(way2.tags, "tunnel")) && !(hasTag(way.tags, "tunnel") && hasTag(way2.tags, "tunnel")))
-          return false;
-        const layer1 = way.tags.layer || "0", layer2 = way2.tags.layer || "0";
-        if (layer1 !== layer2)
-          return false;
-        const level1 = way.tags.level || "0", level2 = way2.tags.level || "0";
-        if (level1 !== level2)
-          return false;
-        return true;
+      if (!(locale2 in _cache2.strings)) {
+        _cache2.strings[locale2] = {};
       }
-      function canConnectByExtend(way, endNodeIdx) {
-        const tipNid = way.nodes[endNodeIdx];
-        const midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2];
-        const tipNode = graph.entity(tipNid);
-        const midNode = graph.entity(midNid);
-        const lon = tipNode.loc[0];
-        const lat = tipNode.loc[1];
-        const lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
-        const lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
-        const queryExtent = geoExtent([
-          [lon - lon_range, lat - lat_range],
-          [lon + lon_range, lat + lat_range]
-        ]);
-        const edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
-        const t = EXTEND_TH_METERS / edgeLen + 1;
-        const extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t);
-        const segmentInfos = tree.waySegments(queryExtent, graph);
-        for (let i2 = 0; i2 < segmentInfos.length; i2++) {
-          let segmentInfo = segmentInfos[i2];
-          let way2 = graph.entity(segmentInfo.wayId);
-          if (!isHighway(way2))
-            continue;
-          if (!canConnectWays(way, way2))
-            continue;
-          let nAid = segmentInfo.nodes[0], nBid = segmentInfo.nodes[1];
-          if (nAid === tipNid || nBid === tipNid)
-            continue;
-          let nA = graph.entity(nAid), nB = graph.entity(nBid);
-          let crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
-          if (crossLoc) {
-            return {
-              mid: midNode,
-              node: tipNode,
-              wid: way2.id,
-              edge: [nA.id, nB.id],
-              cross_loc: crossLoc
-            };
+      const allRequests = items.map((itemType) => {
+        if (itemType in _cache2.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 (".concat(itemType, ") had unexpected data"));
+            return;
           }
-        }
-        return null;
+          const { item: itemInt, color: color2 } = item2;
+          if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color2)) {
+            _cache2.colors[itemInt] = color2;
+          }
+          const { title, detail, fix, trap } = cl2;
+          let issueStrings = {};
+          if (title) issueStrings.title = title.auto;
+          if (detail) issueStrings.detail = marked(detail.auto);
+          if (trap) issueStrings.trap = marked(trap.auto);
+          if (fix) issueStrings.fix = marked(fix.auto);
+          _cache2.strings[locale2][itemType] = issueStrings;
+        };
+        const [item, cl] = itemType.split("-");
+        const url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale2);
+        return json_default(url).then(cacheData);
+      }).filter(Boolean);
+      return Promise.all(allRequests).then(() => _cache2.strings[locale2]);
+    },
+    getStrings(itemType, locale2 = _mainLocalizer.localeCode()) {
+      return locale2 in _cache2.strings ? _cache2.strings[locale2][itemType] : {};
+    },
+    getColor(itemType) {
+      return itemType in _cache2.colors ? _cache2.colors[itemType] : "#FFFFFF";
+    },
+    postUpdate(issue, callback) {
+      if (_cache2.inflightPost[issue.id]) {
+        return callback({ message: "Issue update already inflight", status: -2 }, issue);
       }
-    };
-    validation.type = type3;
-    return validation;
-  }
+      const url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
+      const controller = new AbortController();
+      const after = () => {
+        delete _cache2.inflightPost[issue.id];
+        this.removeItem(issue);
+        if (issue.newStatus === "done") {
+          if (!(issue.item in _cache2.closed)) {
+            _cache2.closed[issue.item] = 0;
+          }
+          _cache2.closed[issue.item] += 1;
+        }
+        if (callback) callback(null, issue);
+      };
+      _cache2.inflightPost[issue.id] = controller;
+      fetch(url, { signal: controller.signal }).then(after).catch((err) => {
+        delete _cache2.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 _cache2.rtree.search(bbox2).map((d2) => d2.data);
+    },
+    // Get a QAItem from cache
+    // NOTE: Don't change method name until UI v3 is merged
+    getError(id2) {
+      return _cache2.data[id2];
+    },
+    // get the name of the icon to display for this item
+    getIcon(itemType) {
+      return _osmoseData.icons[itemType];
+    },
+    // Replace a single QAItem in the cache
+    replaceItem(item) {
+      if (!(item instanceof QAItem) || !item.id) return;
+      _cache2.data[item.id] = item;
+      updateRtree2(encodeIssueRtree2(item), true);
+      return item;
+    },
+    // Remove a single QAItem from the cache
+    removeItem(item) {
+      if (!(item instanceof QAItem) || !item.id) return;
+      delete _cache2.data[item.id];
+      updateRtree2(encodeIssueRtree2(item), false);
+    },
+    // Used to populate `closed:osmose:*` changeset tags
+    getClosedCounts() {
+      return _cache2.closed;
+    },
+    itemURL(item) {
+      return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
+    }
+  };
 
-  // modules/validations/close_nodes.js
-  function validationCloseNodes(context) {
-    var type3 = "close_nodes";
-    var pointThresholdMeters = 0.2;
-    var validation = function(entity, graph) {
-      if (entity.type === "node") {
-        return getIssuesForNode(entity);
-      } else if (entity.type === "way") {
-        return getIssuesForWay(entity);
+  // node_modules/pbf/index.js
+  var SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
+  var SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
+  var TEXT_DECODER_MIN_LENGTH = 12;
+  var utf8TextDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder("utf-8");
+  var PBF_VARINT = 0;
+  var PBF_FIXED64 = 1;
+  var PBF_BYTES = 2;
+  var PBF_FIXED32 = 5;
+  var Pbf = class {
+    /**
+     * @param {Uint8Array | ArrayBuffer} [buf]
+     */
+    constructor(buf = new Uint8Array(16)) {
+      this.buf = ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf);
+      this.dataView = new DataView(this.buf.buffer);
+      this.pos = 0;
+      this.type = 0;
+      this.length = this.buf.length;
+    }
+    // === READING =================================================================
+    /**
+     * @template T
+     * @param {(tag: number, result: T, pbf: Pbf) => void} readField
+     * @param {T} result
+     * @param {number} [end]
+     */
+    readFields(readField, result, end = this.length) {
+      while (this.pos < end) {
+        const val = this.readVarint(), tag2 = val >> 3, startPos = this.pos;
+        this.type = val & 7;
+        readField(tag2, result, this);
+        if (this.pos === startPos) this.skip(val);
       }
-      return [];
-      function getIssuesForNode(node) {
-        var parentWays = graph.parentWays(node);
-        if (parentWays.length) {
-          return getIssuesForVertex(node, parentWays);
+      return result;
+    }
+    /**
+     * @template T
+     * @param {(tag: number, result: T, pbf: Pbf) => void} readField
+     * @param {T} result
+     */
+    readMessage(readField, result) {
+      return this.readFields(readField, result, this.readVarint() + this.pos);
+    }
+    readFixed32() {
+      const val = this.dataView.getUint32(this.pos, true);
+      this.pos += 4;
+      return val;
+    }
+    readSFixed32() {
+      const val = this.dataView.getInt32(this.pos, true);
+      this.pos += 4;
+      return val;
+    }
+    // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
+    readFixed64() {
+      const val = this.dataView.getUint32(this.pos, true) + this.dataView.getUint32(this.pos + 4, true) * SHIFT_LEFT_32;
+      this.pos += 8;
+      return val;
+    }
+    readSFixed64() {
+      const val = this.dataView.getUint32(this.pos, true) + this.dataView.getInt32(this.pos + 4, true) * SHIFT_LEFT_32;
+      this.pos += 8;
+      return val;
+    }
+    readFloat() {
+      const val = this.dataView.getFloat32(this.pos, true);
+      this.pos += 4;
+      return val;
+    }
+    readDouble() {
+      const val = this.dataView.getFloat64(this.pos, true);
+      this.pos += 8;
+      return val;
+    }
+    /**
+     * @param {boolean} [isSigned]
+     */
+    readVarint(isSigned) {
+      const buf = this.buf;
+      let val, b2;
+      b2 = buf[this.pos++];
+      val = b2 & 127;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos++];
+      val |= (b2 & 127) << 7;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos++];
+      val |= (b2 & 127) << 14;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos++];
+      val |= (b2 & 127) << 21;
+      if (b2 < 128) return val;
+      b2 = buf[this.pos];
+      val |= (b2 & 15) << 28;
+      return readVarintRemainder(val, isSigned, this);
+    }
+    readVarint64() {
+      return this.readVarint(true);
+    }
+    readSVarint() {
+      const num = this.readVarint();
+      return num % 2 === 1 ? (num + 1) / -2 : num / 2;
+    }
+    readBoolean() {
+      return Boolean(this.readVarint());
+    }
+    readString() {
+      const end = this.readVarint() + this.pos;
+      const pos = this.pos;
+      this.pos = end;
+      if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
+        return utf8TextDecoder.decode(this.buf.subarray(pos, end));
+      }
+      return readUtf8(this.buf, pos, end);
+    }
+    readBytes() {
+      const end = this.readVarint() + this.pos, buffer = this.buf.subarray(this.pos, end);
+      this.pos = end;
+      return buffer;
+    }
+    // verbose for performance reasons; doesn't affect gzipped size
+    /**
+     * @param {number[]} [arr]
+     * @param {boolean} [isSigned]
+     */
+    readPackedVarint(arr = [], isSigned) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readVarint(isSigned));
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedSVarint(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readSVarint());
+      return arr;
+    }
+    /** @param {boolean[]} [arr] */
+    readPackedBoolean(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readBoolean());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedFloat(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readFloat());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedDouble(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readDouble());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedFixed32(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readFixed32());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedSFixed32(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readSFixed32());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedFixed64(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readFixed64());
+      return arr;
+    }
+    /** @param {number[]} [arr] */
+    readPackedSFixed64(arr = []) {
+      const end = this.readPackedEnd();
+      while (this.pos < end) arr.push(this.readSFixed64());
+      return arr;
+    }
+    readPackedEnd() {
+      return this.type === PBF_BYTES ? this.readVarint() + this.pos : this.pos + 1;
+    }
+    /** @param {number} val */
+    skip(val) {
+      const type2 = val & 7;
+      if (type2 === PBF_VARINT) while (this.buf[this.pos++] > 127) {
+      }
+      else if (type2 === PBF_BYTES) this.pos = this.readVarint() + this.pos;
+      else if (type2 === PBF_FIXED32) this.pos += 4;
+      else if (type2 === PBF_FIXED64) this.pos += 8;
+      else throw new Error("Unimplemented type: ".concat(type2));
+    }
+    // === WRITING =================================================================
+    /**
+     * @param {number} tag
+     * @param {number} type
+     */
+    writeTag(tag2, type2) {
+      this.writeVarint(tag2 << 3 | type2);
+    }
+    /** @param {number} min */
+    realloc(min3) {
+      let length2 = this.length || 16;
+      while (length2 < this.pos + min3) length2 *= 2;
+      if (length2 !== this.length) {
+        const buf = new Uint8Array(length2);
+        buf.set(this.buf);
+        this.buf = buf;
+        this.dataView = new DataView(buf.buffer);
+        this.length = length2;
+      }
+    }
+    finish() {
+      this.length = this.pos;
+      this.pos = 0;
+      return this.buf.subarray(0, this.length);
+    }
+    /** @param {number} val */
+    writeFixed32(val) {
+      this.realloc(4);
+      this.dataView.setInt32(this.pos, val, true);
+      this.pos += 4;
+    }
+    /** @param {number} val */
+    writeSFixed32(val) {
+      this.realloc(4);
+      this.dataView.setInt32(this.pos, val, true);
+      this.pos += 4;
+    }
+    /** @param {number} val */
+    writeFixed64(val) {
+      this.realloc(8);
+      this.dataView.setInt32(this.pos, val & -1, true);
+      this.dataView.setInt32(this.pos + 4, Math.floor(val * SHIFT_RIGHT_32), true);
+      this.pos += 8;
+    }
+    /** @param {number} val */
+    writeSFixed64(val) {
+      this.realloc(8);
+      this.dataView.setInt32(this.pos, val & -1, true);
+      this.dataView.setInt32(this.pos + 4, Math.floor(val * SHIFT_RIGHT_32), true);
+      this.pos += 8;
+    }
+    /** @param {number} val */
+    writeVarint(val) {
+      val = +val || 0;
+      if (val > 268435455 || val < 0) {
+        writeBigVarint(val, this);
+        return;
+      }
+      this.realloc(4);
+      this.buf[this.pos++] = val & 127 | (val > 127 ? 128 : 0);
+      if (val <= 127) return;
+      this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
+      if (val <= 127) return;
+      this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
+      if (val <= 127) return;
+      this.buf[this.pos++] = val >>> 7 & 127;
+    }
+    /** @param {number} val */
+    writeSVarint(val) {
+      this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
+    }
+    /** @param {boolean} val */
+    writeBoolean(val) {
+      this.writeVarint(+val);
+    }
+    /** @param {string} str */
+    writeString(str) {
+      str = String(str);
+      this.realloc(str.length * 4);
+      this.pos++;
+      const startPos = this.pos;
+      this.pos = writeUtf8(this.buf, str, this.pos);
+      const len = this.pos - startPos;
+      if (len >= 128) makeRoomForExtraLength(startPos, len, this);
+      this.pos = startPos - 1;
+      this.writeVarint(len);
+      this.pos += len;
+    }
+    /** @param {number} val */
+    writeFloat(val) {
+      this.realloc(4);
+      this.dataView.setFloat32(this.pos, val, true);
+      this.pos += 4;
+    }
+    /** @param {number} val */
+    writeDouble(val) {
+      this.realloc(8);
+      this.dataView.setFloat64(this.pos, val, true);
+      this.pos += 8;
+    }
+    /** @param {Uint8Array} buffer */
+    writeBytes(buffer) {
+      const len = buffer.length;
+      this.writeVarint(len);
+      this.realloc(len);
+      for (let i3 = 0; i3 < len; i3++) this.buf[this.pos++] = buffer[i3];
+    }
+    /**
+     * @template T
+     * @param {(obj: T, pbf: Pbf) => void} fn
+     * @param {T} obj
+     */
+    writeRawMessage(fn, obj) {
+      this.pos++;
+      const startPos = this.pos;
+      fn(obj, this);
+      const len = this.pos - startPos;
+      if (len >= 128) makeRoomForExtraLength(startPos, len, this);
+      this.pos = startPos - 1;
+      this.writeVarint(len);
+      this.pos += len;
+    }
+    /**
+     * @template T
+     * @param {number} tag
+     * @param {(obj: T, pbf: Pbf) => void} fn
+     * @param {T} obj
+     */
+    writeMessage(tag2, fn, obj) {
+      this.writeTag(tag2, PBF_BYTES);
+      this.writeRawMessage(fn, obj);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedVarint(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedVarint, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedSVarint(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedSVarint, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {boolean[]} arr
+     */
+    writePackedBoolean(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedBoolean, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedFloat(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedFloat, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedDouble(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedDouble, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedFixed32(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedFixed32, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedSFixed32(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedSFixed32, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedFixed64(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedFixed64, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {number[]} arr
+     */
+    writePackedSFixed64(tag2, arr) {
+      if (arr.length) this.writeMessage(tag2, writePackedSFixed64, arr);
+    }
+    /**
+     * @param {number} tag
+     * @param {Uint8Array} buffer
+     */
+    writeBytesField(tag2, buffer) {
+      this.writeTag(tag2, PBF_BYTES);
+      this.writeBytes(buffer);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeFixed32Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED32);
+      this.writeFixed32(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeSFixed32Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED32);
+      this.writeSFixed32(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeFixed64Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED64);
+      this.writeFixed64(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeSFixed64Field(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED64);
+      this.writeSFixed64(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeVarintField(tag2, val) {
+      this.writeTag(tag2, PBF_VARINT);
+      this.writeVarint(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeSVarintField(tag2, val) {
+      this.writeTag(tag2, PBF_VARINT);
+      this.writeSVarint(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {string} str
+     */
+    writeStringField(tag2, str) {
+      this.writeTag(tag2, PBF_BYTES);
+      this.writeString(str);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeFloatField(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED32);
+      this.writeFloat(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {number} val
+     */
+    writeDoubleField(tag2, val) {
+      this.writeTag(tag2, PBF_FIXED64);
+      this.writeDouble(val);
+    }
+    /**
+     * @param {number} tag
+     * @param {boolean} val
+     */
+    writeBooleanField(tag2, val) {
+      this.writeVarintField(tag2, +val);
+    }
+  };
+  function readVarintRemainder(l2, s2, p2) {
+    const buf = p2.buf;
+    let h2, b2;
+    b2 = buf[p2.pos++];
+    h2 = (b2 & 112) >> 4;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 3;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 10;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 17;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 127) << 24;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    b2 = buf[p2.pos++];
+    h2 |= (b2 & 1) << 31;
+    if (b2 < 128) return toNum(l2, h2, s2);
+    throw new Error("Expected varint not more than 10 bytes");
+  }
+  function toNum(low, high, isSigned) {
+    return isSigned ? high * 4294967296 + (low >>> 0) : (high >>> 0) * 4294967296 + (low >>> 0);
+  }
+  function writeBigVarint(val, pbf) {
+    let low, high;
+    if (val >= 0) {
+      low = val % 4294967296 | 0;
+      high = val / 4294967296 | 0;
+    } else {
+      low = ~(-val % 4294967296);
+      high = ~(-val / 4294967296);
+      if (low ^ 4294967295) {
+        low = low + 1 | 0;
+      } else {
+        low = 0;
+        high = high + 1 | 0;
+      }
+    }
+    if (val >= 18446744073709552e3 || val < -18446744073709552e3) {
+      throw new Error("Given varint doesn't fit into 10 bytes");
+    }
+    pbf.realloc(10);
+    writeBigVarintLow(low, high, pbf);
+    writeBigVarintHigh(high, pbf);
+  }
+  function writeBigVarintLow(low, high, pbf) {
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos++] = low & 127 | 128;
+    low >>>= 7;
+    pbf.buf[pbf.pos] = low & 127;
+  }
+  function writeBigVarintHigh(high, pbf) {
+    const lsb = (high & 7) << 4;
+    pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
+    if (!high) return;
+    pbf.buf[pbf.pos++] = high & 127;
+  }
+  function makeRoomForExtraLength(startPos, len, pbf) {
+    const extraLen = len <= 16383 ? 1 : len <= 2097151 ? 2 : len <= 268435455 ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
+    pbf.realloc(extraLen);
+    for (let i3 = pbf.pos - 1; i3 >= startPos; i3--) pbf.buf[i3 + extraLen] = pbf.buf[i3];
+  }
+  function writePackedVarint(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeVarint(arr[i3]);
+  }
+  function writePackedSVarint(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeSVarint(arr[i3]);
+  }
+  function writePackedFloat(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeFloat(arr[i3]);
+  }
+  function writePackedDouble(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeDouble(arr[i3]);
+  }
+  function writePackedBoolean(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeBoolean(arr[i3]);
+  }
+  function writePackedFixed32(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeFixed32(arr[i3]);
+  }
+  function writePackedSFixed32(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeSFixed32(arr[i3]);
+  }
+  function writePackedFixed64(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeFixed64(arr[i3]);
+  }
+  function writePackedSFixed64(arr, pbf) {
+    for (let i3 = 0; i3 < arr.length; i3++) pbf.writeSFixed64(arr[i3]);
+  }
+  function readUtf8(buf, pos, end) {
+    let str = "";
+    let i3 = pos;
+    while (i3 < end) {
+      const b0 = buf[i3];
+      let c2 = null;
+      let bytesPerSequence = b0 > 239 ? 4 : b0 > 223 ? 3 : b0 > 191 ? 2 : 1;
+      if (i3 + bytesPerSequence > end) break;
+      let b1, b2, b3;
+      if (bytesPerSequence === 1) {
+        if (b0 < 128) {
+          c2 = b0;
+        }
+      } else if (bytesPerSequence === 2) {
+        b1 = buf[i3 + 1];
+        if ((b1 & 192) === 128) {
+          c2 = (b0 & 31) << 6 | b1 & 63;
+          if (c2 <= 127) {
+            c2 = null;
+          }
+        }
+      } else if (bytesPerSequence === 3) {
+        b1 = buf[i3 + 1];
+        b2 = buf[i3 + 2];
+        if ((b1 & 192) === 128 && (b2 & 192) === 128) {
+          c2 = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
+          if (c2 <= 2047 || c2 >= 55296 && c2 <= 57343) {
+            c2 = null;
+          }
+        }
+      } else if (bytesPerSequence === 4) {
+        b1 = buf[i3 + 1];
+        b2 = buf[i3 + 2];
+        b3 = buf[i3 + 3];
+        if ((b1 & 192) === 128 && (b2 & 192) === 128 && (b3 & 192) === 128) {
+          c2 = (b0 & 15) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
+          if (c2 <= 65535 || c2 >= 1114112) {
+            c2 = null;
+          }
+        }
+      }
+      if (c2 === null) {
+        c2 = 65533;
+        bytesPerSequence = 1;
+      } else if (c2 > 65535) {
+        c2 -= 65536;
+        str += String.fromCharCode(c2 >>> 10 & 1023 | 55296);
+        c2 = 56320 | c2 & 1023;
+      }
+      str += String.fromCharCode(c2);
+      i3 += bytesPerSequence;
+    }
+    return str;
+  }
+  function writeUtf8(buf, str, pos) {
+    for (let i3 = 0, c2, lead; i3 < str.length; i3++) {
+      c2 = str.charCodeAt(i3);
+      if (c2 > 55295 && c2 < 57344) {
+        if (lead) {
+          if (c2 < 56320) {
+            buf[pos++] = 239;
+            buf[pos++] = 191;
+            buf[pos++] = 189;
+            lead = c2;
+            continue;
+          } else {
+            c2 = lead - 55296 << 10 | c2 - 56320 | 65536;
+            lead = null;
+          }
         } else {
-          return getIssuesForDetachedPoint(node);
+          if (c2 > 56319 || i3 + 1 === str.length) {
+            buf[pos++] = 239;
+            buf[pos++] = 191;
+            buf[pos++] = 189;
+          } else {
+            lead = c2;
+          }
+          continue;
         }
+      } else if (lead) {
+        buf[pos++] = 239;
+        buf[pos++] = 191;
+        buf[pos++] = 189;
+        lead = null;
       }
-      function wayTypeFor(way) {
-        if (way.tags.boundary && way.tags.boundary !== "no")
-          return "boundary";
-        if (way.tags.indoor && way.tags.indoor !== "no")
-          return "indoor";
-        if (way.tags.building && way.tags.building !== "no" || way.tags["building:part"] && way.tags["building:part"] !== "no")
-          return "building";
-        if (osmPathHighwayTagValues[way.tags.highway])
-          return "path";
-        var parentRelations = graph.parentRelations(way);
-        for (var i2 in parentRelations) {
-          var relation = parentRelations[i2];
-          if (relation.tags.type === "boundary")
-            return "boundary";
-          if (relation.isMultipolygon()) {
-            if (relation.tags.indoor && relation.tags.indoor !== "no")
-              return "indoor";
-            if (relation.tags.building && relation.tags.building !== "no" || relation.tags["building:part"] && relation.tags["building:part"] !== "no")
-              return "building";
+      if (c2 < 128) {
+        buf[pos++] = c2;
+      } else {
+        if (c2 < 2048) {
+          buf[pos++] = c2 >> 6 | 192;
+        } else {
+          if (c2 < 65536) {
+            buf[pos++] = c2 >> 12 | 224;
+          } else {
+            buf[pos++] = c2 >> 18 | 240;
+            buf[pos++] = c2 >> 12 & 63 | 128;
           }
+          buf[pos++] = c2 >> 6 & 63 | 128;
         }
-        return "other";
-      }
-      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]);
-        if (hypotenuseMeters < 1.5)
-          return false;
-        return true;
+        buf[pos++] = c2 & 63 | 128;
       }
-      function getIssuesForWay(way) {
-        if (!shouldCheckWay(way))
-          return [];
-        var issues = [], nodes = graph.childNodes(way);
-        for (var i2 = 0; i2 < nodes.length - 1; i2++) {
-          var node1 = nodes[i2];
-          var node2 = nodes[i2 + 1];
-          var issue = getWayIssueIfAny(node1, node2, way);
-          if (issue)
-            issues.push(issue);
-        }
-        return issues;
-      }
-      function getIssuesForVertex(node, parentWays) {
-        var issues = [];
-        function checkForCloseness(node1, node2, way) {
-          var issue = getWayIssueIfAny(node1, node2, way);
-          if (issue)
-            issues.push(issue);
-        }
-        for (var i2 = 0; i2 < parentWays.length; i2++) {
-          var parentWay = parentWays[i2];
-          if (!shouldCheckWay(parentWay))
-            continue;
-          var lastIndex = parentWay.nodes.length - 1;
-          for (var j2 = 0; j2 < parentWay.nodes.length; j2++) {
-            if (j2 !== 0) {
-              if (parentWay.nodes[j2 - 1] === node.id) {
-                checkForCloseness(node, graph.entity(parentWay.nodes[j2]), parentWay);
-              }
-            }
-            if (j2 !== lastIndex) {
-              if (parentWay.nodes[j2 + 1] === node.id) {
-                checkForCloseness(graph.entity(parentWay.nodes[j2]), node, parentWay);
-              }
-            }
-          }
-        }
-        return issues;
-      }
-      function thresholdMetersForWay(way) {
-        if (!shouldCheckWay(way))
-          return 0;
-        var wayType = wayTypeFor(way);
-        if (wayType === "boundary")
-          return 0;
-        if (wayType === "indoor")
-          return 0.01;
-        if (wayType === "building")
-          return 0.05;
-        if (wayType === "path")
-          return 0.1;
-        return 0.2;
-      }
-      function getIssuesForDetachedPoint(node) {
-        var issues = [];
-        var lon = node.loc[0];
-        var lat = node.loc[1];
-        var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
-        var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
-        var queryExtent = geoExtent([
-          [lon - lon_range, lat - lat_range],
-          [lon + lon_range, lat + lat_range]
-        ]);
-        var intersected = context.history().tree().intersects(queryExtent, graph);
-        for (var j2 = 0; j2 < intersected.length; j2++) {
-          var nearby = intersected[j2];
-          if (nearby.id === node.id)
-            continue;
-          if (nearby.type !== "node" || nearby.geometry(graph) !== "point")
-            continue;
-          if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
-            if ("memorial:type" in node.tags && "memorial:type" in nearby.tags && node.tags["memorial:type"] === "stolperstein" && nearby.tags["memorial:type"] === "stolperstein")
-              continue;
-            if ("memorial" in node.tags && "memorial" in nearby.tags && node.tags.memorial === "stolperstein" && nearby.tags.memorial === "stolperstein")
-              continue;
-            var zAxisKeys = { layer: true, level: true, "addr:housenumber": true, "addr:unit": true };
-            var zAxisDifferentiates = false;
-            for (var key in zAxisKeys) {
-              var nodeValue = node.tags[key] || "0";
-              var nearbyValue = nearby.tags[key] || "0";
-              if (nodeValue !== nearbyValue) {
-                zAxisDifferentiates = true;
-                break;
-              }
-            }
-            if (zAxisDifferentiates)
-              continue;
-            issues.push(new validationIssue({
-              type: type3,
-              subtype: "detached",
-              severity: "warning",
-              message: function(context2) {
-                var entity2 = context2.hasEntity(this.entityIds[0]), entity22 = context2.hasEntity(this.entityIds[1]);
-                return entity2 && entity22 ? _t.append("issues.close_nodes.detached.message", {
-                  feature: utilDisplayLabel(entity2, context2.graph()),
-                  feature2: utilDisplayLabel(entity22, context2.graph())
-                }) : "";
-              },
-              reference: showReference,
-              entityIds: [node.id, nearby.id],
-              dynamicFixes: function() {
-                return [
-                  new validationIssueFix({
-                    icon: "iD-operation-disconnect",
-                    title: _t.append("issues.fix.move_points_apart.title")
-                  }),
-                  new validationIssueFix({
-                    icon: "iD-icon-layers",
-                    title: _t.append("issues.fix.use_different_layers_or_levels.title")
-                  })
-                ];
-              }
-            }));
-          }
-        }
-        return issues;
-        function showReference(selection2) {
-          var referenceText = _t("issues.close_nodes.detached.reference");
-          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").html(referenceText);
-        }
-      }
-      function getWayIssueIfAny(node1, node2, way) {
-        if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
-          return null;
-        }
-        if (node1.loc !== node2.loc) {
-          var parentWays1 = graph.parentWays(node1);
-          var parentWays2 = new Set(graph.parentWays(node2));
-          var sharedWays = parentWays1.filter(function(parentWay) {
-            return parentWays2.has(parentWay);
-          });
-          var thresholds = sharedWays.map(function(parentWay) {
-            return thresholdMetersForWay(parentWay);
-          });
-          var threshold = Math.min(...thresholds);
-          var distance = geoSphericalDistance(node1.loc, node2.loc);
-          if (distance > threshold)
-            return null;
-        }
-        return new validationIssue({
-          type: type3,
-          subtype: "vertices",
-          severity: "warning",
-          message: function(context2) {
-            var entity2 = context2.hasEntity(this.entityIds[0]);
-            return entity2 ? _t.append("issues.close_nodes.message", { way: utilDisplayLabel(entity2, context2.graph()) }) : "";
-          },
-          reference: showReference,
-          entityIds: [way.id, node1.id, node2.id],
-          loc: node1.loc,
-          dynamicFixes: function() {
-            return [
-              new validationIssueFix({
-                icon: "iD-icon-plus",
-                title: _t.append("issues.fix.merge_points.title"),
-                onClick: function(context2) {
-                  var entityIds = this.issue.entityIds;
-                  var action = actionMergeNodes([entityIds[1], entityIds[2]]);
-                  context2.perform(action, _t("issues.fix.merge_close_vertices.annotation"));
-                }
-              }),
-              new validationIssueFix({
-                icon: "iD-operation-disconnect",
-                title: _t.append("issues.fix.move_points_apart.title")
-              })
-            ];
-          }
-        });
-        function showReference(selection2) {
-          var referenceText = _t("issues.close_nodes.reference");
-          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").html(referenceText);
-        }
-      }
-    };
-    validation.type = type3;
-    return validation;
+    }
+    return pos;
   }
 
-  // modules/validations/crossing_ways.js
-  function validationCrossingWays(context) {
-    var type3 = "crossing_ways";
-    function getFeatureWithFeatureTypeTagsForWay(way, graph) {
-      if (getFeatureType(way, graph) === null) {
-        var parentRels = graph.parentRelations(way);
-        for (var i2 = 0; i2 < parentRels.length; i2++) {
-          var rel = parentRels[i2];
-          if (getFeatureType(rel, graph) !== null) {
-            return rel;
+  // node_modules/@mapbox/point-geometry/index.js
+  function Point(x2, y2) {
+    this.x = x2;
+    this.y = y2;
+  }
+  Point.prototype = {
+    /**
+     * Clone this point, returning a new point that can be modified
+     * without affecting the old one.
+     * @return {Point} the clone
+     */
+    clone() {
+      return new Point(this.x, this.y);
+    },
+    /**
+     * Add this point's x & y coordinates to another point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    add(p2) {
+      return this.clone()._add(p2);
+    },
+    /**
+     * Subtract this point's x & y coordinates to from point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    sub(p2) {
+      return this.clone()._sub(p2);
+    },
+    /**
+     * Multiply this point's x & y coordinates by point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    multByPoint(p2) {
+      return this.clone()._multByPoint(p2);
+    },
+    /**
+     * Divide this point's x & y coordinates by point,
+     * yielding a new point.
+     * @param {Point} p the other point
+     * @return {Point} output point
+     */
+    divByPoint(p2) {
+      return this.clone()._divByPoint(p2);
+    },
+    /**
+     * Multiply this point's x & y coordinates by a factor,
+     * yielding a new point.
+     * @param {number} k factor
+     * @return {Point} output point
+     */
+    mult(k2) {
+      return this.clone()._mult(k2);
+    },
+    /**
+     * Divide this point's x & y coordinates by a factor,
+     * yielding a new point.
+     * @param {number} k factor
+     * @return {Point} output point
+     */
+    div(k2) {
+      return this.clone()._div(k2);
+    },
+    /**
+     * Rotate this point around the 0, 0 origin by an angle a,
+     * given in radians
+     * @param {number} a angle to rotate around, in radians
+     * @return {Point} output point
+     */
+    rotate(a2) {
+      return this.clone()._rotate(a2);
+    },
+    /**
+     * Rotate this point around p point by an angle a,
+     * given in radians
+     * @param {number} a angle to rotate around, in radians
+     * @param {Point} p Point to rotate around
+     * @return {Point} output point
+     */
+    rotateAround(a2, p2) {
+      return this.clone()._rotateAround(a2, p2);
+    },
+    /**
+     * Multiply this point by a 4x1 transformation matrix
+     * @param {[number, number, number, number]} m transformation matrix
+     * @return {Point} output point
+     */
+    matMult(m2) {
+      return this.clone()._matMult(m2);
+    },
+    /**
+     * Calculate this point but as a unit vector from 0, 0, meaning
+     * that the distance from the resulting point to the 0, 0
+     * coordinate will be equal to 1 and the angle from the resulting
+     * point to the 0, 0 coordinate will be the same as before.
+     * @return {Point} unit vector point
+     */
+    unit() {
+      return this.clone()._unit();
+    },
+    /**
+     * Compute a perpendicular point, where the new y coordinate
+     * is the old x coordinate and the new x coordinate is the old y
+     * coordinate multiplied by -1
+     * @return {Point} perpendicular point
+     */
+    perp() {
+      return this.clone()._perp();
+    },
+    /**
+     * Return a version of this point with the x & y coordinates
+     * rounded to integers.
+     * @return {Point} rounded point
+     */
+    round() {
+      return this.clone()._round();
+    },
+    /**
+     * Return the magnitude of this point: this is the Euclidean
+     * distance from the 0, 0 coordinate to this point's x and y
+     * coordinates.
+     * @return {number} magnitude
+     */
+    mag() {
+      return Math.sqrt(this.x * this.x + this.y * this.y);
+    },
+    /**
+     * Judge whether this point is equal to another point, returning
+     * true or false.
+     * @param {Point} other the other point
+     * @return {boolean} whether the points are equal
+     */
+    equals(other) {
+      return this.x === other.x && this.y === other.y;
+    },
+    /**
+     * Calculate the distance from this point to another point
+     * @param {Point} p the other point
+     * @return {number} distance
+     */
+    dist(p2) {
+      return Math.sqrt(this.distSqr(p2));
+    },
+    /**
+     * Calculate the distance from this point to another point,
+     * without the square root step. Useful if you're comparing
+     * relative distances.
+     * @param {Point} p the other point
+     * @return {number} distance
+     */
+    distSqr(p2) {
+      const dx = p2.x - this.x, dy = p2.y - this.y;
+      return dx * dx + dy * dy;
+    },
+    /**
+     * Get the angle from the 0, 0 coordinate to this point, in radians
+     * coordinates.
+     * @return {number} angle
+     */
+    angle() {
+      return Math.atan2(this.y, this.x);
+    },
+    /**
+     * Get the angle from this point to another point, in radians
+     * @param {Point} b the other point
+     * @return {number} angle
+     */
+    angleTo(b2) {
+      return Math.atan2(this.y - b2.y, this.x - b2.x);
+    },
+    /**
+     * Get the angle between this point and another point, in radians
+     * @param {Point} b the other point
+     * @return {number} angle
+     */
+    angleWith(b2) {
+      return this.angleWithSep(b2.x, b2.y);
+    },
+    /**
+     * Find the angle of the two vectors, solving the formula for
+     * the cross product a x b = |a||b|sin(θ) for θ.
+     * @param {number} x the x-coordinate
+     * @param {number} y the y-coordinate
+     * @return {number} the angle in radians
+     */
+    angleWithSep(x2, y2) {
+      return Math.atan2(
+        this.x * y2 - this.y * x2,
+        this.x * x2 + this.y * y2
+      );
+    },
+    /** @param {[number, number, number, number]} m */
+    _matMult(m2) {
+      const x2 = m2[0] * this.x + m2[1] * this.y, y2 = m2[2] * this.x + m2[3] * this.y;
+      this.x = x2;
+      this.y = y2;
+      return this;
+    },
+    /** @param {Point} p */
+    _add(p2) {
+      this.x += p2.x;
+      this.y += p2.y;
+      return this;
+    },
+    /** @param {Point} p */
+    _sub(p2) {
+      this.x -= p2.x;
+      this.y -= p2.y;
+      return this;
+    },
+    /** @param {number} k */
+    _mult(k2) {
+      this.x *= k2;
+      this.y *= k2;
+      return this;
+    },
+    /** @param {number} k */
+    _div(k2) {
+      this.x /= k2;
+      this.y /= k2;
+      return this;
+    },
+    /** @param {Point} p */
+    _multByPoint(p2) {
+      this.x *= p2.x;
+      this.y *= p2.y;
+      return this;
+    },
+    /** @param {Point} p */
+    _divByPoint(p2) {
+      this.x /= p2.x;
+      this.y /= p2.y;
+      return this;
+    },
+    _unit() {
+      this._div(this.mag());
+      return this;
+    },
+    _perp() {
+      const y2 = this.y;
+      this.y = this.x;
+      this.x = -y2;
+      return this;
+    },
+    /** @param {number} angle */
+    _rotate(angle2) {
+      const cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x2 = cos2 * this.x - sin2 * this.y, y2 = sin2 * this.x + cos2 * this.y;
+      this.x = x2;
+      this.y = y2;
+      return this;
+    },
+    /**
+     * @param {number} angle
+     * @param {Point} p
+     */
+    _rotateAround(angle2, p2) {
+      const cos2 = Math.cos(angle2), sin2 = Math.sin(angle2), x2 = p2.x + cos2 * (this.x - p2.x) - sin2 * (this.y - p2.y), y2 = p2.y + sin2 * (this.x - p2.x) + cos2 * (this.y - p2.y);
+      this.x = x2;
+      this.y = y2;
+      return this;
+    },
+    _round() {
+      this.x = Math.round(this.x);
+      this.y = Math.round(this.y);
+      return this;
+    },
+    constructor: Point
+  };
+  Point.convert = function(p2) {
+    if (p2 instanceof Point) {
+      return (
+        /** @type {Point} */
+        p2
+      );
+    }
+    if (Array.isArray(p2)) {
+      return new Point(+p2[0], +p2[1]);
+    }
+    if (p2.x !== void 0 && p2.y !== void 0) {
+      return new Point(+p2.x, +p2.y);
+    }
+    throw new Error("Expected [x, y] or {x, y} point format");
+  };
+
+  // node_modules/@mapbox/vector-tile/index.js
+  var VectorTileFeature = class {
+    /**
+     * @param {Pbf} pbf
+     * @param {number} end
+     * @param {number} extent
+     * @param {string[]} keys
+     * @param {unknown[]} values
+     */
+    constructor(pbf, end, extent, keys2, values) {
+      this.properties = {};
+      this.extent = extent;
+      this.type = 0;
+      this.id = void 0;
+      this._pbf = pbf;
+      this._geometry = -1;
+      this._keys = keys2;
+      this._values = values;
+      pbf.readFields(readFeature, this, end);
+    }
+    loadGeometry() {
+      const pbf = this._pbf;
+      pbf.pos = this._geometry;
+      const end = pbf.readVarint() + pbf.pos;
+      const lines = [];
+      let line;
+      let cmd = 1;
+      let length2 = 0;
+      let x2 = 0;
+      let y2 = 0;
+      while (pbf.pos < end) {
+        if (length2 <= 0) {
+          const cmdLen = pbf.readVarint();
+          cmd = cmdLen & 7;
+          length2 = cmdLen >> 3;
+        }
+        length2--;
+        if (cmd === 1 || cmd === 2) {
+          x2 += pbf.readSVarint();
+          y2 += pbf.readSVarint();
+          if (cmd === 1) {
+            if (line) lines.push(line);
+            line = [];
+          }
+          if (line) line.push(new Point(x2, y2));
+        } else if (cmd === 7) {
+          if (line) {
+            line.push(line[0].clone());
           }
-        }
+        } else {
+          throw new Error("unknown command ".concat(cmd));
+        }
+      }
+      if (line) lines.push(line);
+      return lines;
+    }
+    bbox() {
+      const pbf = this._pbf;
+      pbf.pos = this._geometry;
+      const end = pbf.readVarint() + pbf.pos;
+      let cmd = 1, length2 = 0, x2 = 0, y2 = 0, x12 = Infinity, x22 = -Infinity, y12 = Infinity, y22 = -Infinity;
+      while (pbf.pos < end) {
+        if (length2 <= 0) {
+          const cmdLen = pbf.readVarint();
+          cmd = cmdLen & 7;
+          length2 = cmdLen >> 3;
+        }
+        length2--;
+        if (cmd === 1 || cmd === 2) {
+          x2 += pbf.readSVarint();
+          y2 += pbf.readSVarint();
+          if (x2 < x12) x12 = x2;
+          if (x2 > x22) x22 = x2;
+          if (y2 < y12) y12 = y2;
+          if (y2 > y22) y22 = y2;
+        } else if (cmd !== 7) {
+          throw new Error("unknown command ".concat(cmd));
+        }
+      }
+      return [x12, y12, x22, y22];
+    }
+    /**
+     * @param {number} x
+     * @param {number} y
+     * @param {number} z
+     * @return {Feature}
+     */
+    toGeoJSON(x2, y2, z2) {
+      const size = this.extent * Math.pow(2, z2), x05 = this.extent * x2, y05 = this.extent * y2, vtCoords = this.loadGeometry();
+      function projectPoint(p2) {
+        return [
+          (p2.x + x05) * 360 / size - 180,
+          360 / Math.PI * Math.atan(Math.exp((1 - (p2.y + y05) * 2 / size) * Math.PI)) - 90
+        ];
       }
-      return way;
-    }
-    function hasTag(tags, key) {
-      return tags[key] !== void 0 && tags[key] !== "no";
+      function projectLine(line) {
+        return line.map(projectPoint);
+      }
+      let geometry;
+      if (this.type === 1) {
+        const points = [];
+        for (const line of vtCoords) {
+          points.push(line[0]);
+        }
+        const coordinates = projectLine(points);
+        geometry = points.length === 1 ? { type: "Point", coordinates: coordinates[0] } : { type: "MultiPoint", coordinates };
+      } else if (this.type === 2) {
+        const coordinates = vtCoords.map(projectLine);
+        geometry = coordinates.length === 1 ? { type: "LineString", coordinates: coordinates[0] } : { type: "MultiLineString", coordinates };
+      } else if (this.type === 3) {
+        const polygons = classifyRings(vtCoords);
+        const coordinates = [];
+        for (const polygon2 of polygons) {
+          coordinates.push(polygon2.map(projectLine));
+        }
+        geometry = coordinates.length === 1 ? { type: "Polygon", coordinates: coordinates[0] } : { type: "MultiPolygon", coordinates };
+      } else {
+        throw new Error("unknown feature type");
+      }
+      const result = {
+        type: "Feature",
+        geometry,
+        properties: this.properties
+      };
+      if (this.id != null) {
+        result.id = this.id;
+      }
+      return result;
     }
-    function taggedAsIndoor(tags) {
-      return hasTag(tags, "indoor") || hasTag(tags, "level") || tags.highway === "corridor";
+  };
+  VectorTileFeature.types = ["Unknown", "Point", "LineString", "Polygon"];
+  function readFeature(tag2, feature3, pbf) {
+    if (tag2 === 1) feature3.id = pbf.readVarint();
+    else if (tag2 === 2) readTag(pbf, feature3);
+    else if (tag2 === 3) feature3.type = /** @type {0 | 1 | 2 | 3} */
+    pbf.readVarint();
+    else if (tag2 === 4) feature3._geometry = pbf.pos;
+  }
+  function readTag(pbf, feature3) {
+    const end = pbf.readVarint() + pbf.pos;
+    while (pbf.pos < end) {
+      const key = feature3._keys[pbf.readVarint()], value = feature3._values[pbf.readVarint()];
+      feature3.properties[key] = value;
+    }
+  }
+  function classifyRings(rings) {
+    const len = rings.length;
+    if (len <= 1) return [rings];
+    const polygons = [];
+    let polygon2, ccw;
+    for (let i3 = 0; i3 < len; i3++) {
+      const area = signedArea(rings[i3]);
+      if (area === 0) continue;
+      if (ccw === void 0) ccw = area < 0;
+      if (ccw === area < 0) {
+        if (polygon2) polygons.push(polygon2);
+        polygon2 = [rings[i3]];
+      } else if (polygon2) {
+        polygon2.push(rings[i3]);
+      }
+    }
+    if (polygon2) polygons.push(polygon2);
+    return polygons;
+  }
+  function signedArea(ring) {
+    let sum = 0;
+    for (let i3 = 0, len = ring.length, j2 = len - 1, p1, p2; i3 < len; j2 = i3++) {
+      p1 = ring[i3];
+      p2 = ring[j2];
+      sum += (p2.x - p1.x) * (p1.y + p2.y);
+    }
+    return sum;
+  }
+  var VectorTileLayer = class {
+    /**
+     * @param {Pbf} pbf
+     * @param {number} [end]
+     */
+    constructor(pbf, end) {
+      this.version = 1;
+      this.name = "";
+      this.extent = 4096;
+      this.length = 0;
+      this._pbf = pbf;
+      this._keys = [];
+      this._values = [];
+      this._features = [];
+      pbf.readFields(readLayer, this, end);
+      this.length = this._features.length;
+    }
+    /** return feature `i` from this layer as a `VectorTileFeature`
+     * @param {number} i
+     */
+    feature(i3) {
+      if (i3 < 0 || i3 >= this._features.length) throw new Error("feature index out of bounds");
+      this._pbf.pos = this._features[i3];
+      const end = this._pbf.readVarint() + this._pbf.pos;
+      return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
     }
-    function allowsBridge(featureType) {
-      return featureType === "highway" || featureType === "railway" || featureType === "waterway";
+  };
+  function readLayer(tag2, layer, pbf) {
+    if (tag2 === 15) layer.version = pbf.readVarint();
+    else if (tag2 === 1) layer.name = pbf.readString();
+    else if (tag2 === 5) layer.extent = pbf.readVarint();
+    else if (tag2 === 2) layer._features.push(pbf.pos);
+    else if (tag2 === 3) layer._keys.push(pbf.readString());
+    else if (tag2 === 4) layer._values.push(readValueMessage(pbf));
+  }
+  function readValueMessage(pbf) {
+    let value = null;
+    const end = pbf.readVarint() + pbf.pos;
+    while (pbf.pos < end) {
+      const tag2 = pbf.readVarint() >> 3;
+      value = tag2 === 1 ? pbf.readString() : tag2 === 2 ? pbf.readFloat() : tag2 === 3 ? pbf.readDouble() : tag2 === 4 ? pbf.readVarint64() : tag2 === 5 ? pbf.readVarint() : tag2 === 6 ? pbf.readSVarint() : tag2 === 7 ? pbf.readBoolean() : null;
     }
-    function allowsTunnel(featureType) {
-      return featureType === "highway" || featureType === "railway" || featureType === "waterway";
+    return value;
+  }
+  var VectorTile = class {
+    /**
+     * @param {Pbf} pbf
+     * @param {number} [end]
+     */
+    constructor(pbf, end) {
+      this.layers = pbf.readFields(readTile, {}, end);
     }
-    var ignoredBuildings = {
-      demolished: true,
-      dismantled: true,
-      proposed: true,
-      razed: true
-    };
-    function getFeatureType(entity, graph) {
-      var geometry = entity.geometry(graph);
-      if (geometry !== "line" && geometry !== "area")
-        return null;
-      var tags = entity.tags;
-      if (hasTag(tags, "building") && !ignoredBuildings[tags.building])
-        return "building";
-      if (hasTag(tags, "highway") && osmRoutableHighwayTagValues[tags.highway])
-        return "highway";
-      if (geometry !== "line")
-        return null;
-      if (hasTag(tags, "railway") && osmRailwayTrackTagValues[tags.railway])
-        return "railway";
-      if (hasTag(tags, "waterway") && osmFlowingWaterwayTagValues[tags.waterway])
-        return "waterway";
-      return null;
+  };
+  function readTile(tag2, layers, pbf) {
+    if (tag2 === 3) {
+      const layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
+      if (layer.length) layers[layer.name] = layer;
     }
-    function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
-      var level1 = tags1.level || "0";
-      var level2 = tags2.level || "0";
-      if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
-        return true;
+  }
+
+  // modules/services/mapillary.js
+  var accessToken = "MLY|4100327730013843|5bb78b81720791946a9a7b956c57b7cf";
+  var apiUrl = "https://graph.mapillary.com/";
+  var baseTileUrl = "https://tiles.mapillary.com/maps/vtp";
+  var mapFeatureTileUrl = "".concat(baseTileUrl, "/mly_map_feature_point/2/{z}/{x}/{y}?access_token=").concat(accessToken);
+  var tileUrl = "".concat(baseTileUrl, "/mly1_public/2/{z}/{x}/{y}?access_token=").concat(accessToken);
+  var trafficSignTileUrl = "".concat(baseTileUrl, "/mly_map_feature_traffic_sign/2/{z}/{x}/{y}?access_token=").concat(accessToken);
+  var viewercss = "mapillary-js/mapillary.css";
+  var viewerjs = "mapillary-js/mapillary.js";
+  var minZoom = 14;
+  var dispatch4 = 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"];
+  var _isViewerOpen = false;
+  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 = "".concat(tile.id, "-").concat(which);
+    if (cache.loaded[tileId] || cache.inflight[tileId]) return;
+    const controller = new AbortController();
+    cache.inflight[tileId] = controller;
+    const requestUrl = url.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace("{z}", tile.xyz[2]);
+    fetch(requestUrl, { signal: controller.signal }).then(function(response) {
+      if (!response.ok) {
+        throw new Error(response.status + " " + response.statusText);
       }
-      var layer1 = tags1.layer || "0";
-      var layer2 = tags2.layer || "0";
-      if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
-        if (hasTag(tags1, "bridge") && !hasTag(tags2, "bridge"))
-          return true;
-        if (!hasTag(tags1, "bridge") && hasTag(tags2, "bridge"))
-          return true;
-        if (hasTag(tags1, "bridge") && hasTag(tags2, "bridge") && layer1 !== layer2)
-          return true;
-      } else if (allowsBridge(featureType1) && hasTag(tags1, "bridge"))
-        return true;
-      else if (allowsBridge(featureType2) && hasTag(tags2, "bridge"))
-        return true;
-      if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
-        if (hasTag(tags1, "tunnel") && !hasTag(tags2, "tunnel"))
-          return true;
-        if (!hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel"))
-          return true;
-        if (hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel") && layer1 !== layer2)
-          return true;
-      } else if (allowsTunnel(featureType1) && hasTag(tags1, "tunnel"))
-        return true;
-      else if (allowsTunnel(featureType2) && hasTag(tags2, "tunnel"))
-        return true;
-      if (featureType1 === "waterway" && featureType2 === "highway" && tags2.man_made === "pier")
-        return true;
-      if (featureType2 === "waterway" && featureType1 === "highway" && tags1.man_made === "pier")
-        return true;
-      if (featureType1 === "building" || featureType2 === "building" || taggedAsIndoor(tags1) || taggedAsIndoor(tags2)) {
-        if (layer1 !== layer2)
-          return true;
+      cache.loaded[tileId] = true;
+      delete cache.inflight[tileId];
+      return response.arrayBuffer();
+    }).then(function(data) {
+      if (!data) {
+        throw new Error("No Data");
       }
-      return false;
-    }
-    var highwaysDisallowingFords = {
-      motorway: true,
-      motorway_link: true,
-      trunk: true,
-      trunk_link: true,
-      primary: true,
-      primary_link: true,
-      secondary: true,
-      secondary_link: true
-    };
-    var nonCrossingHighways = { track: true };
-    function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
-      var featureType1 = getFeatureType(entity1, graph);
-      var featureType2 = getFeatureType(entity2, graph);
-      var geometry1 = entity1.geometry(graph);
-      var geometry2 = entity2.geometry(graph);
-      var bothLines = geometry1 === "line" && geometry2 === "line";
-      if (featureType1 === featureType2) {
-        if (featureType1 === "highway") {
-          var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
-          var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
-          if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
-            var roadFeature = entity1IsPath ? entity2 : entity1;
-            if (nonCrossingHighways[roadFeature.tags.highway]) {
-              return {};
-            }
-            var pathFeature = entity1IsPath ? entity1 : entity2;
-            if (["marked", "unmarked", "traffic_signals"].indexOf(pathFeature.tags.crossing) !== -1) {
-              return bothLines ? { highway: "crossing", crossing: pathFeature.tags.crossing } : {};
-            }
-            return bothLines ? { highway: "crossing" } : {};
-          }
-          return {};
-        }
-        if (featureType1 === "waterway")
-          return {};
-        if (featureType1 === "railway")
-          return {};
-      } else {
-        var featureTypes = [featureType1, featureType2];
-        if (featureTypes.indexOf("highway") !== -1) {
-          if (featureTypes.indexOf("railway") !== -1) {
-            if (!bothLines)
-              return {};
-            var isTram = entity1.tags.railway === "tram" || entity2.tags.railway === "tram";
-            if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
-              if (isTram)
-                return { railway: "tram_crossing" };
-              return { railway: "crossing" };
-            } else {
-              if (isTram)
-                return { railway: "tram_level_crossing" };
-              return { railway: "level_crossing" };
-            }
-          }
-          if (featureTypes.indexOf("waterway") !== -1) {
-            if (hasTag(entity1.tags, "tunnel") && hasTag(entity2.tags, "tunnel"))
-              return null;
-            if (hasTag(entity1.tags, "bridge") && hasTag(entity2.tags, "bridge"))
-              return null;
-            if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
-              return null;
-            }
-            return bothLines ? { ford: "yes" } : {};
-          }
-        }
+      loadTileDataToCache(data, tile, which);
+      if (which === "images") {
+        dispatch4.call("loadedImages");
+      } else if (which === "signs") {
+        dispatch4.call("loadedSigns");
+      } else if (which === "points") {
+        dispatch4.call("loadedMapFeatures");
+      }
+    }).catch(function() {
+      cache.loaded[tileId] = true;
+      delete cache.inflight[tileId];
+    });
+  }
+  function loadTileDataToCache(data, tile, which) {
+    const vectorTile = new VectorTile(new Pbf(data));
+    let features, cache, layer, i3, feature3, loc, d2;
+    if (vectorTile.layers.hasOwnProperty("image")) {
+      features = [];
+      cache = _mlyCache.images;
+      layer = vectorTile.layers.image;
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d2 = {
+          loc,
+          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[d2.id] = d2;
+        features.push({
+          minX: loc[0],
+          minY: loc[1],
+          maxX: loc[0],
+          maxY: loc[1],
+          data: d2
+        });
+      }
+      if (cache.rtree) {
+        cache.rtree.load(features);
       }
-      return null;
     }
-    function findCrossingsByWay(way1, graph, tree) {
-      var edgeCrossInfos = [];
-      if (way1.type !== "way")
-        return edgeCrossInfos;
-      var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
-      var way1FeatureType = getFeatureType(taggedFeature1, graph);
-      if (way1FeatureType === null)
-        return edgeCrossInfos;
-      var checkedSingleCrossingWays = {};
-      var i2, j2;
-      var extent;
-      var n1, n2, nA, nB, nAId, nBId;
-      var segment1, segment2;
-      var oneOnly;
-      var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
-      var way1Nodes = graph.childNodes(way1);
-      var comparedWays = {};
-      for (i2 = 0; i2 < way1Nodes.length - 1; i2++) {
-        n1 = way1Nodes[i2];
-        n2 = way1Nodes[i2 + 1];
-        extent = 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])
-          ]
-        ]);
-        segmentInfos = tree.waySegments(extent, graph);
-        for (j2 = 0; j2 < segmentInfos.length; j2++) {
-          segment2Info = segmentInfos[j2];
-          if (segment2Info.wayId === way1.id)
-            continue;
-          if (checkedSingleCrossingWays[segment2Info.wayId])
-            continue;
-          comparedWays[segment2Info.wayId] = true;
-          way2 = graph.hasEntity(segment2Info.wayId);
-          if (!way2)
-            continue;
-          taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph);
-          way2FeatureType = getFeatureType(taggedFeature2, graph);
-          if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
-            continue;
-          }
-          oneOnly = way1FeatureType === "building" || way2FeatureType === "building";
-          nAId = segment2Info.nodes[0];
-          nBId = segment2Info.nodes[1];
-          if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
-            continue;
-          }
-          nA = graph.hasEntity(nAId);
-          if (!nA)
-            continue;
-          nB = graph.hasEntity(nBId);
-          if (!nB)
-            continue;
-          segment1 = [n1.loc, n2.loc];
-          segment2 = [nA.loc, nB.loc];
-          var point = geoLineIntersection(segment1, segment2);
-          if (point) {
-            edgeCrossInfos.push({
-              wayInfos: [
-                {
-                  way: way1,
-                  featureType: way1FeatureType,
-                  edge: [n1.id, n2.id]
-                },
-                {
-                  way: way2,
-                  featureType: way2FeatureType,
-                  edge: [nA.id, nB.id]
-                }
-              ],
-              crossPoint: point
-            });
-            if (oneOnly) {
-              checkedSingleCrossingWays[way2.id] = true;
-              break;
-            }
-          }
+    if (vectorTile.layers.hasOwnProperty("sequence")) {
+      features = [];
+      cache = _mlyCache.sequences;
+      layer = vectorTile.layers.sequence;
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        if (cache.lineString[feature3.properties.id]) {
+          cache.lineString[feature3.properties.id].push(feature3);
+        } else {
+          cache.lineString[feature3.properties.id] = [feature3];
         }
       }
-      return edgeCrossInfos;
     }
-    function waysToCheck(entity, graph) {
-      var featureType = getFeatureType(entity, graph);
-      if (!featureType)
-        return [];
-      if (entity.type === "way") {
-        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")) {
-            var entity2 = graph.hasEntity(member.id);
-            if (entity2 && array2.indexOf(entity2) === -1) {
-              array2.push(entity2);
-            }
-          }
-          return array2;
-        }, []);
+    if (vectorTile.layers.hasOwnProperty("point")) {
+      features = [];
+      cache = _mlyCache[which];
+      layer = vectorTile.layers.point;
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d2 = {
+          loc,
+          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: d2
+        });
       }
-      return [];
-    }
-    var validation = function checkCrossingWays(entity, graph) {
-      var tree = context.history().tree();
-      var ways = waysToCheck(entity, graph);
-      var issues = [];
-      var wayIndex, crossingIndex, crossings;
-      for (wayIndex in ways) {
-        crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
-        for (crossingIndex in crossings) {
-          issues.push(createIssue(crossings[crossingIndex], graph));
-        }
+      if (cache.rtree) {
+        cache.rtree.load(features);
       }
-      return issues;
-    };
-    function createIssue(crossing, graph) {
-      crossing.wayInfos.sort(function(way1Info, way2Info) {
-        var type1 = way1Info.featureType;
-        var type22 = way2Info.featureType;
-        if (type1 === type22) {
-          return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
-        } else if (type1 === "waterway") {
-          return true;
-        } else if (type22 === "waterway") {
-          return false;
-        }
-        return type1 < type22;
-      });
-      var entities = crossing.wayInfos.map(function(wayInfo) {
-        return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
-      });
-      var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
-      var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
-      var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
-      var featureType1 = crossing.wayInfos[0].featureType;
-      var featureType2 = crossing.wayInfos[1].featureType;
-      var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
-      var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, "tunnel") && allowsTunnel(featureType2) && hasTag(entities[1].tags, "tunnel");
-      var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, "bridge") && allowsBridge(featureType2) && hasTag(entities[1].tags, "bridge");
-      var subtype = [featureType1, featureType2].sort().join("-");
-      var crossingTypeID = subtype;
-      if (isCrossingIndoors) {
-        crossingTypeID = "indoor-indoor";
-      } else if (isCrossingTunnels) {
-        crossingTypeID = "tunnel-tunnel";
-      } else if (isCrossingBridges) {
-        crossingTypeID = "bridge-bridge";
+    }
+    if (vectorTile.layers.hasOwnProperty("traffic_sign")) {
+      features = [];
+      cache = _mlyCache[which];
+      layer = vectorTile.layers.traffic_sign;
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d2 = {
+          loc,
+          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: d2
+        });
       }
-      if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
-        crossingTypeID += "_connectable";
+      if (cache.rtree) {
+        cache.rtree.load(features);
       }
-      var uniqueID = crossing.crossPoint[0].toFixed(4) + "," + crossing.crossPoint[1].toFixed(4);
-      return new validationIssue({
-        type: type3,
-        subtype,
-        severity: "warning",
-        message: function(context2) {
-          var graph2 = context2.graph();
-          var entity1 = graph2.hasEntity(this.entityIds[0]), entity2 = graph2.hasEntity(this.entityIds[1]);
-          return entity1 && entity2 ? _t.append("issues.crossing_ways.message", {
-            feature: utilDisplayLabel(entity1, graph2),
-            feature2: utilDisplayLabel(entity2, graph2)
-          }) : "";
-        },
-        reference: showReference,
-        entityIds: entities.map(function(entity) {
-          return entity.id;
-        }),
-        data: {
-          edges,
-          featureTypes,
-          connectionTags
-        },
-        hash: uniqueID,
-        loc: crossing.crossPoint,
-        dynamicFixes: function(context2) {
-          var mode = context2.mode();
-          if (!mode || mode.id !== "select" || mode.selectedIDs().length !== 1)
-            return [];
-          var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
-          var selectedFeatureType = this.data.featureTypes[selectedIndex];
-          var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
-          var fixes = [];
-          if (connectionTags) {
-            fixes.push(makeConnectWaysFix(this.data.connectionTags));
-          }
-          if (isCrossingIndoors) {
-            fixes.push(new validationIssueFix({
-              icon: "iD-icon-layers",
-              title: _t.append("issues.fix.use_different_levels.title")
-            }));
-          } else if (isCrossingTunnels || isCrossingBridges || featureType1 === "building" || featureType2 === "building") {
-            fixes.push(makeChangeLayerFix("higher"));
-            fixes.push(makeChangeLayerFix("lower"));
-          } else if (context2.graph().geometry(this.entityIds[0]) === "line" && context2.graph().geometry(this.entityIds[1]) === "line") {
-            if (allowsBridge(selectedFeatureType) && selectedFeatureType !== "waterway") {
-              fixes.push(makeAddBridgeOrTunnelFix("add_a_bridge", "temaki-bridge", "bridge"));
-            }
-            var skipTunnelFix = otherFeatureType === "waterway" && selectedFeatureType !== "waterway";
-            if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
-              fixes.push(makeAddBridgeOrTunnelFix("add_a_tunnel", "temaki-tunnel", "tunnel"));
-            }
-          }
-          fixes.push(new validationIssueFix({
-            icon: "iD-operation-move",
-            title: _t.append("issues.fix.reposition_features.title")
-          }));
-          return fixes;
-        }
+    }
+  }
+  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 z2 = geoScaleToZoom(projection2.scale());
+    const z22 = Math.ceil(z2 * 2) / 2 + 2.5;
+    const tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map(function(tile) {
+      return tile.extent;
+    });
+  }
+  function 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(d2) {
+        return d2.data;
       });
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.crossing_ways." + crossingTypeID + ".reference"));
+      return found.length ? result.concat(found) : result;
+    }, []);
+  }
+  var mapillary_default = {
+    // Initialize Mapillary
+    init: function() {
+      if (!_mlyCache) {
+        this.reset();
       }
-    }
-    function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
-      return new validationIssueFix({
-        icon: iconName,
-        title: _t.append("issues.fix." + fixTitleID + ".title"),
-        onClick: function(context2) {
-          var mode = context2.mode();
-          if (!mode || mode.id !== "select")
-            return;
-          var selectedIDs = mode.selectedIDs();
-          if (selectedIDs.length !== 1)
-            return;
-          var selectedWayID = selectedIDs[0];
-          if (!context2.hasEntity(selectedWayID))
-            return;
-          var resultWayIDs = [selectedWayID];
-          var edge, crossedEdge, crossedWayID;
-          if (this.issue.entityIds[0] === selectedWayID) {
-            edge = this.issue.data.edges[0];
-            crossedEdge = this.issue.data.edges[1];
-            crossedWayID = this.issue.entityIds[1];
-          } else {
-            edge = this.issue.data.edges[1];
-            crossedEdge = this.issue.data.edges[0];
-            crossedWayID = this.issue.entityIds[0];
-          }
-          var crossingLoc = this.issue.loc;
-          var projection2 = context2.projection;
-          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);
-            if (!structLengthMeters) {
-              structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
-            }
-            if (structLengthMeters) {
-              if (getFeatureType(crossedWay, graph) === "railway") {
-                structLengthMeters *= 2;
-              }
-            } else {
-              structLengthMeters = 8;
-            }
-            var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection2) + Math.PI;
-            var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection2) + Math.PI;
-            var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
-            if (crossingAngle > Math.PI)
-              crossingAngle -= Math.PI;
-            structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2;
-            structLengthMeters += 4;
-            structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
-            function geomToProj(geoPoint) {
-              return [
-                geoLonToMeters(geoPoint[0], geoPoint[1]),
-                geoLatToMeters(geoPoint[1])
-              ];
-            }
-            function projToGeom(projPoint) {
-              var lat = geoMetersToLat(projPoint[1]);
-              return [
-                geoMetersToLon(projPoint[0], lat),
-                lat
-              ];
-            }
-            var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
-            var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
-            var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
-            var projectedCrossingLoc = geomToProj(crossingLoc);
-            var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
-            function locSphericalDistanceFromCrossingLoc(angle2, distanceMeters) {
-              var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
-              return projToGeom([
-                projectedCrossingLoc[0] + Math.cos(angle2) * lengthSphericalMeters,
-                projectedCrossingLoc[1] + Math.sin(angle2) * lengthSphericalMeters
-              ]);
-            }
-            var endpointLocGetter1 = function(lengthMeters) {
-              return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
-            };
-            var endpointLocGetter2 = function(lengthMeters) {
-              return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
-            };
-            var minEdgeLengthMeters = 0.55;
-            function determineEndpoint(edge2, endNode, locGetter) {
-              var newNode;
-              var idealLengthMeters = structLengthMeters / 2;
-              var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
-              if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
-                var idealNodeLoc = locGetter(idealLengthMeters);
-                newNode = osmNode();
-                graph = actionAddMidpoint({ loc: idealNodeLoc, edge: edge2 }, newNode)(graph);
-              } else {
-                var edgeCount = 0;
-                endNode.parentIntersectionWays(graph).forEach(function(way) {
-                  way.nodes.forEach(function(nodeID) {
-                    if (nodeID === endNode.id) {
-                      if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
-                        edgeCount += 1;
-                      } else {
-                        edgeCount += 2;
-                      }
-                    }
-                  });
-                });
-                if (edgeCount >= 3) {
-                  var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
-                  if (insetLength > minEdgeLengthMeters) {
-                    var insetNodeLoc = locGetter(insetLength);
-                    newNode = osmNode();
-                    graph = actionAddMidpoint({ loc: insetNodeLoc, edge: edge2 }, newNode)(graph);
-                  }
-                }
-              }
-              if (!newNode)
-                newNode = endNode;
-              var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs);
-              graph = splitAction(graph);
-              if (splitAction.getCreatedWayIDs().length) {
-                resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
-              }
-              return newNode;
-            }
-            var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
-            var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
-            var structureWay = resultWayIDs.map(function(id2) {
-              return graph.entity(id2);
-            }).find(function(way) {
-              return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
-            });
-            var tags = Object.assign({}, structureWay.tags);
-            if (bridgeOrTunnel === "bridge") {
-              tags.bridge = "yes";
-              tags.layer = "1";
-            } else {
-              var tunnelValue = "yes";
-              if (getFeatureType(structureWay, graph) === "waterway") {
-                tunnelValue = "culvert";
-              }
-              tags.tunnel = tunnelValue;
-              tags.layer = "-1";
-            }
-            graph = actionChangeTags(structureWay.id, tags)(graph);
-            return graph;
-          };
-          context2.perform(action, _t("issues.fix." + fixTitleID + ".annotation"));
-          context2.enter(modeSelect(context2, resultWayIDs));
+      this.event = utilRebind(this, dispatch4, "on");
+    },
+    // Reset cache and state
+    reset: function() {
+      if (_mlyCache) {
+        Object.values(_mlyCache.requests.inflight).forEach(function(request3) {
+          request3.abort();
+        });
+      }
+      _mlyCache = {
+        images: { rtree: new RBush(), forImageId: {} },
+        image_detections: { forImageId: {} },
+        signs: { rtree: new RBush() },
+        points: { rtree: new RBush() },
+        sequences: { rtree: new RBush(), 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(d2) {
+        if (d2.data.sequence_id) {
+          sequenceIds[d2.data.sequence_id] = true;
         }
       });
-    }
-    function makeConnectWaysFix(connectionTags) {
-      var fixTitleID = "connect_features";
-      if (connectionTags.ford) {
-        fixTitleID = "connect_using_ford";
-      }
-      return new validationIssueFix({
-        icon: "iD-icon-crossing",
-        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 });
-              graph = graph.replace(node);
-              var nodesToMerge = [node.id];
-              var mergeThresholdInMeters = 0.75;
-              edges.forEach(function(edge) {
-                var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
-                var nearby = geoSphericalClosestNode(edgeNodes, loc);
-                if ((!nearby.node.hasInterestingTags() || nearby.node.isCrossing()) && nearby.distance < mergeThresholdInMeters) {
-                  nodesToMerge.push(nearby.node.id);
-                } else {
-                  graph = actionAddMidpoint({ loc, edge }, node)(graph);
-                }
-              });
-              if (nodesToMerge.length > 1) {
-                graph = actionMergeNodes(nodesToMerge, loc)(graph);
-              }
-              return graph;
-            },
-            _t("issues.fix.connect_crossing_features.annotation")
-          );
+      Object.keys(sequenceIds).forEach(function(sequenceId) {
+        if (_mlyCache.sequences.lineString[sequenceId]) {
+          lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
         }
       });
-    }
-    function makeChangeLayerFix(higherOrLower) {
-      return new validationIssueFix({
-        icon: "iD-icon-" + (higherOrLower === "higher" ? "up" : "down"),
-        title: _t.append("issues.fix.tag_this_as_" + higherOrLower + ".title"),
-        onClick: function(context2) {
-          var mode = context2.mode();
-          if (!mode || mode.id !== "select")
-            return;
-          var selectedIDs = mode.selectedIDs();
-          if (selectedIDs.length !== 1)
-            return;
-          var selectedID = selectedIDs[0];
-          if (!this.issue.entityIds.some(function(entityId) {
-            return entityId === selectedID;
-          }))
-            return;
-          var entity = context2.hasEntity(selectedID);
-          if (!entity)
-            return;
-          var tags = Object.assign({}, entity.tags);
-          var layer = tags.layer && Number(tags.layer);
-          if (layer && !isNaN(layer)) {
-            if (higherOrLower === "higher") {
-              layer += 1;
-            } else {
-              layer -= 1;
-            }
-          } else {
-            if (higherOrLower === "higher") {
-              layer = 1;
-            } else {
-              layer = -1;
-            }
-          }
-          tags.layer = layer.toString();
-          context2.perform(
-            actionChangeTags(entity.id, tags),
-            _t("operations.change_tags.annotation")
-          );
+      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);
       });
-    }
-    validation.type = type3;
-    return validation;
-  }
-
-  // modules/behavior/draw_way.js
-  function behaviorDrawWay(context, wayID, mode, startGraph) {
-    const keybinding = utilKeybinding("drawWay");
-    var dispatch10 = dispatch_default("rejectedSelfIntersection");
-    var behavior = behaviorDraw(context);
-    var _nodeIndex;
-    var _origWay;
-    var _wayGeometry;
-    var _headNodeID;
-    var _annotation;
-    var _pointerHasMoved = false;
-    var _drawNode;
-    var _didResolveTempEdit = false;
-    function createDrawNode(loc) {
-      _drawNode = osmNode({ loc });
-      context.pauseChangeDispatch();
-      context.replace(function actionAddDrawNode(graph) {
-        var way = graph.entity(wayID);
-        return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
-      }, _annotation);
-      context.resumeChangeDispatch();
-      setActiveElements();
-    }
-    function removeDrawNode() {
-      context.pauseChangeDispatch();
-      context.replace(
-        function actionDeleteDrawNode(graph) {
-          var way = graph.entity(wayID);
-          return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
-        },
-        _annotation
+      return _loadViewerPromise;
+    },
+    // Load traffic sign image sprites
+    loadSignResources: function(context) {
+      context.ui().svgDefs.addSprites(
+        ["mapillary-sprite"],
+        false
+        /* don't override colors */
       );
-      _drawNode = void 0;
-      context.resumeChangeDispatch();
-    }
-    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 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 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();
       }
-    }
-    function allowsVertex(d) {
-      return d.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d, context.graph());
-    }
-    function move(d3_event, datum2) {
-      var loc = context.map().mouseCoordinates();
-      if (!_drawNode)
-        createDrawNode(loc);
-      context.surface().classed("nope-disabled", d3_event.altKey);
-      var targetLoc = datum2 && datum2.properties && datum2.properties.entity && allowsVertex(datum2.properties.entity) && datum2.properties.entity.loc;
-      var targetNodes = datum2 && datum2.properties && datum2.properties.nodes;
-      if (targetLoc) {
-        loc = targetLoc;
-      } else if (targetNodes) {
-        var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
-        if (choice) {
-          loc = choice.loc;
-        }
+    },
+    // Show map feature detections in image viewer
+    showFeatureDetections: function(value) {
+      _mlyShowFeatureDetections = value;
+      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
+        this.resetTags();
       }
-      context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
-      _drawNode = context.entity(_drawNode.id);
-      checkGeometry(true);
-    }
-    function checkGeometry(includeDrawNode) {
-      var nopeDisabled = context.surface().classed("nope-disabled");
-      var isInvalid = isInvalidGeometry(includeDrawNode);
-      if (nopeDisabled) {
-        context.surface().classed("nope", false).classed("nope-suppressed", isInvalid);
-      } else {
-        context.surface().classed("nope", isInvalid).classed("nope-suppressed", false);
+    },
+    // Show traffic sign detections in image viewer
+    showSignDetections: function(value) {
+      _mlyShowSignDetections = value;
+      if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
+        this.resetTags();
       }
-    }
-    function isInvalidGeometry(includeDrawNode) {
-      var testNode = _drawNode;
-      var parentWay = context.graph().entity(wayID);
-      var nodes = context.graph().childNodes(parentWay).slice();
-      if (includeDrawNode) {
-        if (parentWay.isClosed()) {
-          nodes.pop();
-        }
-      } else {
-        if (parentWay.isClosed()) {
-          if (nodes.length < 3)
-            return false;
-          if (_drawNode)
-            nodes.splice(-2, 1);
-          testNode = nodes[nodes.length - 2];
-        } else {
-          return false;
-        }
-      }
-      return testNode && geoHasSelfIntersections(nodes, testNode.id);
-    }
-    function undone() {
-      _didResolveTempEdit = true;
-      context.pauseChangeDispatch();
-      var nextMode;
-      if (context.graph() === startGraph) {
-        nextMode = modeSelect(context, [wayID]);
-      } else {
-        context.pop(1);
-        nextMode = mode;
+    },
+    // 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()]);
       }
-      context.perform(actionNoop());
-      context.pop(1);
-      context.resumeChangeDispatch();
-      context.enter(nextMode);
-    }
-    function setActiveElements() {
-      if (!_drawNode)
-        return;
-      context.surface().selectAll("." + _drawNode.id).classed("active", true);
-    }
-    function resetToStartGraph() {
-      while (context.graph() !== startGraph) {
-        context.pop();
+      if (toDate) {
+        filter2.push([">=", "capturedAt", new Date(toDate).getTime()]);
       }
-    }
-    var drawWay = function(surface) {
-      _drawNode = void 0;
-      _didResolveTempEdit = false;
-      _origWay = context.entity(wayID);
-      if (typeof _nodeIndex === "number") {
-        _headNodeID = _origWay.nodes[_nodeIndex];
-      } else if (_origWay.isClosed()) {
-        _headNodeID = _origWay.nodes[_origWay.nodes.length - 2];
-      } else {
-        _headNodeID = _origWay.nodes[_origWay.nodes.length - 1];
+      if (_mlyViewer) {
+        _mlyViewer.setFilter(filter2);
       }
-      _wayGeometry = _origWay.geometry(context.graph());
-      _annotation = _t(
-        (_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? "operations.start.annotation." : "operations.continue.annotation.") + _wayGeometry
-      );
-      _pointerHasMoved = false;
-      context.pauseChangeDispatch();
-      context.perform(actionNoop(), _annotation);
-      context.resumeChangeDispatch();
-      behavior.hover().initialNodeID(_headNodeID);
-      behavior.on("move", function() {
-        _pointerHasMoved = true;
-        move.apply(this, arguments);
-      }).on("down", function() {
-        move.apply(this, arguments);
-      }).on("downcancel", function() {
-        if (_drawNode)
-          removeDrawNode();
-      }).on("click", drawWay.add).on("clickWay", drawWay.addWay).on("clickNode", drawWay.addNode).on("undo", context.undo).on("cancel", drawWay.cancel).on("finish", drawWay.finish);
-      select_default2(window).on("keydown.drawWay", keydown).on("keyup.drawWay", keyup);
-      context.map().dblclickZoomEnable(false).on("drawn.draw", setActiveElements);
-      setActiveElements();
-      surface.call(behavior);
-      context.history().on("undone.draw", undone);
-    };
-    drawWay.off = function(surface) {
-      if (!_didResolveTempEdit) {
-        context.pauseChangeDispatch();
-        resetToStartGraph();
-        context.resumeChangeDispatch();
+      _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();
       }
-      _drawNode = void 0;
-      _nodeIndex = void 0;
-      context.map().on("drawn.draw", null);
-      surface.call(behavior.off).selectAll(".active").classed("active", false);
-      surface.classed("nope", false).classed("nope-suppressed", false).classed("nope-disabled", false);
-      select_default2(window).on("keydown.drawWay", null).on("keyup.drawWay", null);
-      context.history().on("undone.draw", null);
-    };
-    function attemptAdd(d, loc, doAdd) {
-      if (_drawNode) {
-        context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
-        _drawNode = context.entity(_drawNode.id);
-      } else {
-        createDrawNode(loc);
+      _isViewerOpen = true;
+      return this;
+    },
+    // Hide the image viewer and resets map markers
+    hideViewer: function(context) {
+      _mlyActiveImage = null;
+      if (!_mlyFallback && _mlyViewer) {
+        _mlyViewer.getComponent("sequence").stop();
       }
-      checkGeometry(true);
-      if (d && d.properties && d.properties.nope || context.surface().classed("nope")) {
-        if (!_pointerHasMoved) {
-          removeDrawNode();
+      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);
+      dispatch4.call("imageChanged");
+      dispatch4.call("loadedMapFeatures");
+      dispatch4.call("loadedSigns");
+      _isViewerOpen = false;
+      return this.setStyles(context, null);
+    },
+    // Get viewer status
+    isViewerOpen: function() {
+      return _isViewerOpen;
+    },
+    // Update the URL with current image id
+    updateUrlImage: function(imageId) {
+      if (!window.mocha) {
+        const hash = utilStringQs(window.location.hash);
+        if (imageId) {
+          hash.photo = "mapillary/" + imageId;
+        } else {
+          delete hash.photo;
         }
-        dispatch10.call("rejectedSelfIntersection", this);
-        return;
+        window.location.replace("#" + utilQsString(hash, true));
       }
-      context.pauseChangeDispatch();
-      doAdd();
-      _didResolveTempEdit = true;
-      context.resumeChangeDispatch();
-      context.enter(mode);
-    }
-    drawWay.add = function(loc, d) {
-      attemptAdd(d, loc, function() {
-      });
-    };
-    drawWay.addWay = function(loc, edge, d) {
-      attemptAdd(d, loc, function() {
-        context.replace(
-          actionAddMidpoint({ loc, edge }, _drawNode),
-          _annotation
-        );
-      });
-    };
-    drawWay.addNode = function(node, d) {
-      if (node.id === _headNodeID || _origWay.isClosed() && node.id === _origWay.first()) {
-        drawWay.finish();
-        return;
+    },
+    // Highlight the detection in the viewer that is related to the clicked map feature
+    highlightDetection: function(detection) {
+      if (detection) {
+        _mlyHighlightedDetection = detection.id;
       }
-      attemptAdd(d, node.loc, function() {
-        context.replace(
-          function actionReplaceDrawNode(graph) {
-            graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
-            return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
-          },
-          _annotation
-        );
+      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 getFeatureType(ways) {
-      if (ways.every((way) => way.isClosed()))
-        return "area";
-      if (ways.every((way) => !way.isClosed()))
-        return "line";
-      return "generic";
-    }
-    function followMode() {
-      if (_didResolveTempEdit)
-        return;
-      try {
-        const isDrawingArea = _origWay.nodes[0] === _origWay.nodes.slice(-1)[0];
-        const [secondLastNodeId, lastNodeId] = _origWay.nodes.slice(isDrawingArea ? -3 : -2);
-        const historyGraph = context.history().graph();
-        if (!lastNodeId || !secondLastNodeId || !historyGraph.hasEntity(lastNodeId) || !historyGraph.hasEntity(secondLastNodeId)) {
-          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("operations.follow.error.needs_more_initial_nodes"))();
-          return;
-        }
-        const lastNodesParents = historyGraph.parentWays(historyGraph.entity(lastNodeId)).filter((w) => w.id !== wayID);
-        const secondLastNodesParents = historyGraph.parentWays(historyGraph.entity(secondLastNodeId)).filter((w) => w.id !== wayID);
-        const featureType = getFeatureType(lastNodesParents);
-        if (lastNodesParents.length !== 1 || secondLastNodesParents.length === 0) {
-          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append(`operations.follow.error.intersection_of_multiple_ways.${featureType}`))();
-          return;
-        }
-        if (!secondLastNodesParents.some((n2) => n2.id === lastNodesParents[0].id)) {
-          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append(`operations.follow.error.intersection_of_different_ways.${featureType}`))();
-          return;
+      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, "".concat(apiUrl, "/").concat(image.id, "/detections?access_token=").concat(accessToken, "&fields=id,image,geometry,value"));
         }
-        const way = lastNodesParents[0];
-        const indexOfLast = way.nodes.indexOf(lastNodeId);
-        const indexOfSecondLast = way.nodes.indexOf(secondLastNodeId);
-        const isDescendingPastZero = indexOfLast === way.nodes.length - 2 && indexOfSecondLast === 0;
-        let nextNodeIndex = indexOfLast + (indexOfLast > indexOfSecondLast && !isDescendingPastZero ? 1 : -1);
-        if (nextNodeIndex === -1)
-          nextNodeIndex = indexOfSecondLast === 1 ? way.nodes.length - 2 : 1;
-        const nextNode = historyGraph.entity(way.nodes[nextNodeIndex]);
-        drawWay.addNode(nextNode, {
-          geometry: { type: "Point", coordinates: nextNode.loc },
-          id: nextNode.id,
-          properties: { target: true, entity: nextNode }
-        });
-      } catch (ex) {
-        context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("operations.follow.error.unknown"))();
-      }
-    }
-    keybinding.on(_t("operations.follow.key"), followMode);
-    select_default2(document).call(keybinding);
-    drawWay.finish = function() {
-      checkGeometry(false);
-      if (context.surface().classed("nope")) {
-        dispatch10.call("rejectedSelfIntersection", this);
-        return;
+        dispatch4.call("imageChanged");
       }
-      context.pauseChangeDispatch();
-      context.pop(1);
-      _didResolveTempEdit = true;
-      context.resumeChangeDispatch();
-      var way = context.hasEntity(wayID);
-      if (!way || way.isDegenerate()) {
-        drawWay.cancel();
-        return;
+      function bearingChanged(e3) {
+        dispatch4.call("bearingChanged", void 0, e3);
       }
-      window.setTimeout(function() {
-        context.map().dblclickZoomEnable(true);
-      }, 1e3);
-      var isNewFeature = !mode.isContinuing;
-      context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
-    };
-    drawWay.cancel = function() {
-      context.pauseChangeDispatch();
-      resetToStartGraph();
-      context.resumeChangeDispatch();
-      window.setTimeout(function() {
-        context.map().dblclickZoomEnable(true);
-      }, 1e3);
-      context.surface().classed("nope", false).classed("nope-disabled", false).classed("nope-suppressed", false);
-      context.enter(modeBrowse(context));
-    };
-    drawWay.nodeIndex = function(val) {
-      if (!arguments.length)
-        return _nodeIndex;
-      _nodeIndex = val;
-      return drawWay;
-    };
-    drawWay.activeID = function() {
-      if (!arguments.length)
-        return _drawNode && _drawNode.id;
-      return drawWay;
-    };
-    return utilRebind(drawWay, dispatch10, "on");
-  }
-
-  // modules/modes/draw_line.js
-  function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
-    var mode = {
-      button,
-      id: "draw-line"
-    };
-    var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on("rejectedSelfIntersection.modeDrawLine", function() {
-      context.ui().flash.iconName("#iD-icon-no").label(_t.append("self_intersection.error.lines"))();
-    });
-    mode.wayID = wayID;
-    mode.isContinuing = continuing;
-    mode.enter = function() {
-      behavior.nodeIndex(affix === "prefix" ? 0 : void 0);
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
-    };
-    mode.selectedIDs = function() {
-      return [wayID];
-    };
-    mode.activeID = function() {
-      return behavior && behavior.activeID() || [];
-    };
-    return mode;
-  }
-
-  // modules/validations/disconnected_way.js
-  function validationDisconnectedWay() {
-    var type3 = "disconnected_way";
-    function isTaggedAsHighway(entity) {
-      return osmRoutableHighwayTagValues[entity.tags.highway];
-    }
-    var validation = function checkDisconnectedWay(entity, graph) {
-      var routingIslandWays = routingIslandForEntity(entity);
-      if (!routingIslandWays)
-        return [];
-      return [new validationIssue({
-        type: type3,
-        subtype: "highway",
-        severity: "warning",
-        message: function(context) {
-          var entity2 = this.entityIds.length && context.hasEntity(this.entityIds[0]);
-          var label = entity2 && utilDisplayLabel(entity2, context.graph());
-          return _t.append("issues.disconnected_way.routable.message", { count: this.entityIds.length, highway: label });
-        },
-        reference: showReference,
-        entityIds: Array.from(routingIslandWays).map(function(way) {
-          return way.id;
-        }),
-        dynamicFixes: makeFixes
-      })];
-      function makeFixes(context) {
-        var fixes = [];
-        var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
-        if (singleEntity) {
-          if (singleEntity.type === "way" && !singleEntity.isClosed()) {
-            var textDirection = _mainLocalizer.textDirection();
-            var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), "start");
-            if (startFix)
-              fixes.push(startFix);
-            var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), "end");
-            if (endFix)
-              fixes.push(endFix);
-          }
-          if (!fixes.length) {
-            fixes.push(new validationIssueFix({
-              title: _t.append("issues.fix.connect_feature.title")
-            }));
-          }
-          fixes.push(new validationIssueFix({
-            icon: "iD-operation-delete",
-            title: _t.append("issues.fix.delete_feature.title"),
-            entityIds: [singleEntity.id],
-            onClick: function(context2) {
-              var id2 = this.issue.entityIds[0];
-              var operation = operationDelete(context2, [id2]);
-              if (!operation.disabled()) {
-                operation();
-              }
-            }
-          }));
-        } else {
-          fixes.push(new validationIssueFix({
-            title: _t.append("issues.fix.connect_features.title")
-          }));
-        }
-        return fixes;
+    },
+    // Move to an image
+    selectImage: function(context, imageId) {
+      if (_mlyViewer && imageId) {
+        _mlyViewer.moveTo(imageId).catch(function(e3) {
+          console.error("mly3", e3);
+        });
       }
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.disconnected_way.routable.reference"));
+      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("".concat(apiUrl, "/").concat(id2, "/detections?access_token=").concat(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;
       }
-      function routingIslandForEntity(entity2) {
-        var routingIsland = /* @__PURE__ */ new Set();
-        var waysToCheck = [];
-        function queueParentWays(node) {
-          graph.parentWays(node).forEach(function(parentWay) {
-            if (!routingIsland.has(parentWay) && isRoutableWay(parentWay, false)) {
-              routingIsland.add(parentWay);
-              waysToCheck.push(parentWay);
+    },
+    // 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(d2) {
+        return d2.sequence_id === selectedSequenceId || d2.id === hoveredImageId;
+      }).classed("hovered", function(d2) {
+        return d2.id === hoveredImageId;
+      });
+      context.container().selectAll(".layer-mapillary .sequence").classed("highlighted", function(d2) {
+        return d2.properties.id === hoveredSequenceId;
+      }).classed("currentView", function(d2) {
+        return d2.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 tag2 = makeTag(data);
+          if (tag2) {
+            tagComponent.add([tag2]);
+          }
+        });
+      }
+      function makeTag(data) {
+        const valueParts = data.value.split("--");
+        if (!valueParts.length) return;
+        let tag2;
+        let text;
+        let color2 = 16777215;
+        if (_mlyHighlightedDetection === data.id) {
+          color2 = 16776960;
+          text = valueParts[1];
+          if (text === "flat" || text === "discrete" || text === "sign") {
+            text = valueParts[2];
+          }
+          text = text.replace(/-/g, " ");
+          text = text.charAt(0).toUpperCase() + text.slice(1);
+          _mlyHighlightedDetection = null;
         }
-        if (entity2.type === "way" && isRoutableWay(entity2, true)) {
-          routingIsland.add(entity2);
-          waysToCheck.push(entity2);
-        } else if (entity2.type === "node" && isRoutableNode(entity2)) {
-          routingIsland.add(entity2);
-          queueParentWays(entity2);
-        } else {
-          return null;
+        var decodedGeometry = window.atob(data.geometry);
+        var uintArray = new Uint8Array(decodedGeometry.length);
+        for (var i3 = 0; i3 < decodedGeometry.length; i3++) {
+          uintArray[i3] = decodedGeometry.charCodeAt(i3);
         }
-        while (waysToCheck.length) {
-          var wayToCheck = waysToCheck.pop();
-          var childNodes = graph.childNodes(wayToCheck);
-          for (var i2 in childNodes) {
-            var vertex = childNodes[i2];
-            if (isConnectedVertex(vertex)) {
-              return null;
-            }
-            if (isRoutableNode(vertex)) {
-              routingIsland.add(vertex);
-            }
-            queueParentWays(vertex);
+        const tile = new VectorTile(new Pbf(uintArray.buffer));
+        const layer = tile.layers["mpy-or"];
+        const geometries = layer.feature(0).loadGeometry();
+        const polygon2 = geometries.map((ring) => ring.map((point) => [point.x / layer.extent, point.y / layer.extent]));
+        tag2 = new mapillary.OutlineTag(
+          data.id,
+          new mapillary.PolygonGeometry(polygon2[0]),
+          {
+            text,
+            textColor: color2,
+            lineColor: color2,
+            lineWidth: 2,
+            fillColor: color2,
+            fillOpacity: 0.3
           }
-        }
-        return routingIsland;
+        );
+        return tag2;
       }
-      function isConnectedVertex(vertex) {
-        var osm = services.osm;
-        if (osm && !osm.isDataLoaded(vertex.loc))
-          return true;
-        if (vertex.tags.entrance && vertex.tags.entrance !== "no")
-          return true;
-        if (vertex.tags.amenity === "parking_entrance")
-          return true;
-        return false;
+    },
+    // 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);
       }
-      function isRoutableNode(node) {
-        if (node.tags.highway === "elevator")
-          return true;
-        return false;
+      if (this.subtype) {
+        parts.push(this.subtype);
       }
-      function isRoutableWay(way, ignoreInnerWays) {
-        if (isTaggedAsHighway(way) || way.tags.route === "ferry")
-          return true;
-        return graph.parentRelations(way).some(function(parentRelation) {
-          if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry")
-            return true;
-          if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== "inner"))
-            return true;
-          return false;
-        });
+      if (this.entityIds) {
+        var entityKeys = this.entityIds.slice().sort();
+        parts.push.apply(parts, entityKeys);
       }
-      function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
-        var vertex = graph.hasEntity(vertexID);
-        if (!vertex || vertex.tags.noexit === "yes")
-          return null;
-        var useLeftContinue = whichEnd === "start" && textDirection === "ltr" || whichEnd === "end" && textDirection === "rtl";
-        return new validationIssueFix({
-          icon: "iD-operation-continue" + (useLeftContinue ? "-left" : ""),
-          title: _t.append("issues.fix.continue_from_" + whichEnd + ".title"),
-          entityIds: [vertexID],
-          onClick: function(context) {
-            var wayId = this.issue.entityIds[0];
-            var way = context.hasEntity(wayId);
-            var vertexId = this.entityIds[0];
-            var vertex2 = context.hasEntity(vertexId);
-            if (!way || !vertex2)
-              return;
-            var map2 = context.map();
-            if (!context.editable() || !map2.trimmedExtent().contains(vertex2.loc)) {
-              map2.zoomToEase(vertex2);
-            }
-            context.enter(
-              modeDrawLine(context, wayId, context.graph(), "line", way.affix(vertexId), true)
-            );
+      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;
     };
-    validation.type = type3;
-    return validation;
+  }
+  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/validations/invalid_format.js
-  function validationFormatting() {
-    var type3 = "invalid_format";
-    var validation = function(entity) {
-      var issues = [];
-      function isValidEmail(email) {
-        var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i;
-        return !email || valid_email.test(email);
+  // modules/services/maprules.js
+  var buildRuleChecks = function() {
+    return {
+      equals: function(equals) {
+        return function(tags) {
+          return Object.keys(equals).every(function(k2) {
+            return equals[k2] === tags[k2];
+          });
+        };
+      },
+      notEquals: function(notEquals) {
+        return function(tags) {
+          return Object.keys(notEquals).some(function(k2) {
+            return notEquals[k2] !== tags[k2];
+          });
+        };
+      },
+      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]);
+        };
       }
-      function showReferenceEmail(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.invalid_format.email.reference"));
+    };
+  };
+  var buildLineKeys = function() {
+    return {
+      highway: {
+        rest_area: true,
+        services: true
+      },
+      railway: {
+        roundhouse: true,
+        station: true,
+        traverser: true,
+        turntable: true,
+        wash: true
       }
-      if (entity.tags.email) {
-        var emails = entity.tags.email.split(";").map(function(s) {
-          return s.trim();
-        }).filter(function(x) {
-          return !isValidEmail(x);
+    };
+  };
+  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, "");
         });
-        if (emails.length) {
-          issues.push(new validationIssue({
-            type: type3,
-            subtype: "email",
-            severity: "warning",
-            message: function(context) {
-              var entity2 = context.hasEntity(this.entityIds[0]);
-              return entity2 ? _t.append(
-                "issues.invalid_format.email.message" + this.data,
-                { feature: utilDisplayLabel(entity2, context.graph()), email: emails.join(", ") }
-              ) : "";
-            },
-            reference: showReferenceEmail,
-            entityIds: [entity.id],
-            hash: emails.join(),
-            data: emails.length > 1 ? "_multi" : ""
-          }));
+      };
+      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";
         }
       }
-      return issues;
-    };
-    validation.type = type3;
-    return validation;
-  }
-
-  // modules/validations/help_request.js
-  function validationHelpRequest(context) {
-    var type3 = "help_request";
-    var validation = function checkFixmeTag(entity) {
-      if (!entity.tags.fixme)
-        return [];
-      if (entity.version === void 0)
-        return [];
-      if (entity.v !== void 0) {
-        var baseEntity = context.history().base().hasEntity(entity.id);
-        if (!baseEntity || !baseEntity.tags.fixme)
-          return [];
+      for (var key in tagMap) {
+        if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
+          return "area";
+        }
+        if (key in _lineKeys && keyValueImpliesLine(key)) {
+          return "area";
+        }
       }
-      return [new validationIssue({
-        type: type3,
-        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)
-          }) : "";
+      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);
+          });
         },
-        dynamicFixes: function() {
-          return [
-            new validationIssueFix({
-              title: _t.append("issues.fix.address_the_concern.title")
-            })
-          ];
+        // 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);
+          }
         },
-        reference: showReference,
-        entityIds: [entity.id]
-      })];
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.fixme_tag.reference"));
-      }
-    };
-    validation.type = type3;
-    return validation;
-  }
+        // 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/validations/impossible_oneway.js
-  function validationImpossibleOneway() {
-    var type3 = "impossible_oneway";
-    var validation = function checkImpossibleOneway(entity, graph) {
-      if (entity.type !== "way" || entity.geometry(graph) !== "line")
-        return [];
-      if (entity.isClosed())
-        return [];
-      if (!typeForWay(entity))
-        return [];
-      if (!isOneway(entity))
-        return [];
-      var firstIssues = issuesForNode(entity, entity.first());
-      var lastIssues = issuesForNode(entity, entity.last());
-      return firstIssues.concat(lastIssues);
-      function typeForWay(way) {
-        if (way.geometry(graph) !== "line")
-          return null;
-        if (osmRoutableHighwayTagValues[way.tags.highway])
-          return "highway";
-        if (osmFlowingWaterwayTagValues[way.tags.waterway])
-          return "waterway";
-        return null;
+  // 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 h2 = head.entities[id2];
+      var b2 = base.entities[id2];
+      if (h2 === b2) return;
+      if (_changes[id2]) return;
+      if (!h2 && b2) {
+        _changes[id2] = { base: b2, head: h2 };
+        _didChange.deletion = true;
+        return;
       }
-      function isOneway(way) {
-        if (way.tags.oneway === "yes")
-          return true;
-        if (way.tags.oneway)
-          return false;
-        for (var key in way.tags) {
-          if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
-            return true;
+      if (h2 && !b2) {
+        _changes[id2] = { base: b2, head: h2 };
+        _didChange.addition = true;
+        return;
+      }
+      if (h2 && b2) {
+        if (h2.members && b2.members && !(0, import_fast_deep_equal3.default)(h2.members, b2.members)) {
+          _changes[id2] = { base: b2, head: h2 };
+          _didChange.geometry = true;
+          _didChange.properties = true;
+          return;
+        }
+        if (h2.loc && b2.loc && !geoVecEqual(h2.loc, b2.loc)) {
+          _changes[id2] = { base: b2, head: h2 };
+          _didChange.geometry = true;
+        }
+        if (h2.nodes && b2.nodes && !(0, import_fast_deep_equal3.default)(h2.nodes, b2.nodes)) {
+          _changes[id2] = { base: b2, head: h2 };
+          _didChange.geometry = true;
+        }
+        if (h2.tags && b2.tags && !(0, import_fast_deep_equal3.default)(h2.tags, b2.tags)) {
+          _changes[id2] = { base: b2, head: h2 };
+          _didChange.properties = true;
+        }
+      }
+    }
+    function load() {
+      var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
+      for (var i3 = 0; i3 < ids.length; i3++) {
+        checkEntityID(ids[i3]);
+      }
+    }
+    load();
+    _diff.length = function length2() {
+      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 h2 = _changes[id2].head;
+        var b2 = _changes[id2].base;
+        var entity = h2 || b2;
+        if (includeRelMembers && entity.type === "relation") {
+          var mh = h2 ? h2.members.map(function(m2) {
+            return m2.id;
+          }) : [];
+          var mb = b2 ? b2.members.map(function(m2) {
+            return m2.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 i3 = 0; i3 < keys2.length; i3++) {
+        var change = _changes[keys2[i3]];
+        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 false;
       }
-      function nodeOccursMoreThanOnce(way, nodeID) {
-        var occurrences = 0;
-        for (var index in way.nodes) {
-          if (way.nodes[index] === nodeID) {
-            occurrences += 1;
-            if (occurrences > 1)
-              return true;
+      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");
           }
         }
-        return false;
       }
-      function isConnectedViaOtherTypes(way, node) {
-        var wayType = typeForWay(way);
-        if (wayType === "highway") {
-          if (node.tags.entrance && node.tags.entrance !== "no")
-            return true;
-          if (node.tags.amenity === "parking_entrance")
-            return true;
-        } else if (wayType === "waterway") {
-          if (node.id === way.first()) {
-            if (node.tags.natural === "spring")
-              return true;
-          } else {
-            if (node.tags.manhole === "drain")
-              return true;
+    };
+    _diff.complete = function complete(extent) {
+      var result = {};
+      var id2, change;
+      for (id2 in _changes) {
+        change = _changes[id2];
+        var h2 = change.head;
+        var b2 = change.base;
+        var entity = h2 || b2;
+        var i3;
+        if (extent && (!h2 || !h2.intersects(extent, head)) && (!b2 || !b2.intersects(extent, base))) {
+          continue;
+        }
+        result[id2] = h2;
+        if (entity.type === "way") {
+          var nh = h2 ? h2.nodes : [];
+          var nb = b2 ? b2.nodes : [];
+          var diff;
+          diff = utilArrayDifference(nh, nb);
+          for (i3 = 0; i3 < diff.length; i3++) {
+            result[diff[i3]] = head.hasEntity(diff[i3]);
+          }
+          diff = utilArrayDifference(nb, nh);
+          for (i3 = 0; i3 < diff.length; i3++) {
+            result[diff[i3]] = head.hasEntity(diff[i3]);
           }
         }
-        return graph.parentWays(node).some(function(parentWay) {
-          if (parentWay.id === way.id)
-            return false;
-          if (wayType === "highway") {
-            if (parentWay.geometry(graph) === "area" && osmRoutableHighwayTagValues[parentWay.tags.highway])
-              return true;
-            if (parentWay.tags.route === "ferry")
-              return true;
-            return graph.parentRelations(parentWay).some(function(parentRelation) {
-              if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry")
-                return true;
-              return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
-            });
-          } else if (wayType === "waterway") {
-            if (parentWay.tags.natural === "water" || parentWay.tags.natural === "coastline")
-              return true;
+        if (entity.type === "relation" && entity.isMultipolygon()) {
+          var mh = h2 ? h2.members.map(function(m2) {
+            return m2.id;
+          }) : [];
+          var mb = b2 ? b2.members.map(function(m2) {
+            return m2.id;
+          }) : [];
+          var ids = utilArrayUnion(mh, mb);
+          for (i3 = 0; i3 < ids.length; i3++) {
+            var member = head.hasEntity(ids[i3]);
+            if (!member) continue;
+            if (extent && !member.intersects(extent, head)) continue;
+            result[ids[i3]] = member;
           }
-          return false;
-        });
+        }
+        addParents(head.parentWays(entity), result);
+        addParents(head.parentRelations(entity), result);
       }
-      function issuesForNode(way, nodeID) {
-        var isFirst = nodeID === way.first();
-        var wayType = typeForWay(way);
-        if (nodeOccursMoreThanOnce(way, nodeID))
-          return [];
-        var osm = services.osm;
-        if (!osm)
-          return [];
-        var node = graph.hasEntity(nodeID);
-        if (!node || !osm.isDataLoaded(node.loc))
-          return [];
-        if (isConnectedViaOtherTypes(way, node))
-          return [];
-        var attachedWaysOfSameType = graph.parentWays(node).filter(function(parentWay) {
-          if (parentWay.id === way.id)
-            return false;
-          return typeForWay(parentWay) === wayType;
-        });
-        if (wayType === "waterway" && attachedWaysOfSameType.length === 0)
-          return [];
-        var attachedOneways = attachedWaysOfSameType.filter(function(attachedWay) {
-          return isOneway(attachedWay);
-        });
-        if (attachedOneways.length < attachedWaysOfSameType.length)
-          return [];
-        if (attachedOneways.length) {
-          var connectedEndpointsOkay = attachedOneways.some(function(attachedOneway) {
-            if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID)
-              return true;
-            if (nodeOccursMoreThanOnce(attachedOneway, nodeID))
-              return true;
-            return false;
-          });
-          if (connectedEndpointsOkay)
-            return [];
-        }
-        var placement = isFirst ? "start" : "end", messageID = wayType + ".", referenceID = wayType + ".";
-        if (wayType === "waterway") {
-          messageID += "connected." + placement;
-          referenceID += "connected";
-        } else {
-          messageID += placement;
-          referenceID += placement;
-        }
-        return [new validationIssue({
-          type: type3,
-          subtype: wayType,
-          severity: "warning",
-          message: function(context) {
-            var entity2 = context.hasEntity(this.entityIds[0]);
-            return entity2 ? _t.append("issues.impossible_oneway." + messageID + ".message", {
-              feature: utilDisplayLabel(entity2, context.graph())
-            }) : "";
-          },
-          reference: getReference(referenceID),
-          entityIds: [way.id, node.id],
-          dynamicFixes: function() {
-            var fixes = [];
-            if (attachedOneways.length) {
-              fixes.push(new validationIssueFix({
-                icon: "iD-operation-reverse",
-                title: _t.append("issues.fix.reverse_feature.title"),
-                entityIds: [way.id],
-                onClick: function(context) {
-                  var id2 = this.issue.entityIds[0];
-                  context.perform(actionReverse(id2), _t("operations.reverse.annotation.line", { n: 1 }));
-                }
-              }));
-            }
-            if (node.tags.noexit !== "yes") {
-              var textDirection = _mainLocalizer.textDirection();
-              var useLeftContinue = isFirst && textDirection === "ltr" || !isFirst && textDirection === "rtl";
-              fixes.push(new validationIssueFix({
-                icon: "iD-operation-continue" + (useLeftContinue ? "-left" : ""),
-                title: _t.append("issues.fix.continue_from_" + (isFirst ? "start" : "end") + ".title"),
-                onClick: function(context) {
-                  var entityID = this.issue.entityIds[0];
-                  var vertexID = this.issue.entityIds[1];
-                  var way2 = context.entity(entityID);
-                  var vertex = context.entity(vertexID);
-                  continueDrawing(way2, vertex, context);
-                }
-              }));
-            }
-            return fixes;
-          },
-          loc: node.loc
-        })];
-        function getReference(referenceID2) {
-          return function showReference(selection2) {
-            selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.impossible_oneway." + referenceID2 + ".reference"));
-          };
+      return result;
+      function addParents(parents, result2) {
+        for (var i4 = 0; i4 < parents.length; i4++) {
+          var parent = parents[i4];
+          if (parent.id in result2) continue;
+          result2[parent.id] = parent;
+          addParents(head.parentRelations(parent), result2);
         }
       }
     };
-    function continueDrawing(way, vertex, context) {
-      var map2 = context.map();
-      if (!context.editable() || !map2.trimmedExtent().contains(vertex.loc)) {
-        map2.zoomToEase(vertex);
-      }
-      context.enter(
-        modeDrawLine(context, way.id, context.graph(), "line", way.affix(vertex.id), true)
-      );
-    }
-    validation.type = type3;
-    return validation;
+    return _diff;
   }
 
-  // modules/validations/incompatible_source.js
-  function validationIncompatibleSource() {
-    const type3 = "incompatible_source";
-    const incompatibleRules = [
-      {
-        id: "amap",
-        regex: /(^amap$|^amap\.com|autonavi|mapabc|高德)/i
-      },
-      {
-        id: "baidu",
-        regex: /(baidu|mapbar|百度)/i
-      },
-      {
-        id: "google",
-        regex: /google/i,
-        exceptRegex: /((books|drive)\.google|google\s?(books|drive|plus))|(esri\/Google_Africa_Buildings)/i
-      }
-    ];
-    const validation = function checkIncompatibleSource(entity) {
-      const entitySources = entity.tags && entity.tags.source && entity.tags.source.split(";");
-      if (!entitySources)
-        return [];
-      const entityID = entity.id;
-      return entitySources.map((source) => {
-        const matchRule = incompatibleRules.find((rule) => {
-          if (!rule.regex.test(source))
-            return false;
-          if (rule.exceptRegex && rule.exceptRegex.test(source))
-            return false;
-          return true;
-        });
-        if (!matchRule)
-          return null;
-        return new validationIssue({
-          type: type3,
-          severity: "warning",
-          message: (context) => {
-            const entity2 = context.hasEntity(entityID);
-            return entity2 ? _t.append("issues.incompatible_source.feature.message", {
-              feature: utilDisplayLabel(entity2, context.graph(), true),
-              value: source
-            }) : "";
-          },
-          reference: getReference(matchRule.id),
-          entityIds: [entityID],
-          hash: source,
-          dynamicFixes: () => {
-            return [
-              new validationIssueFix({ title: _t.append("issues.fix.remove_proprietary_data.title") })
-            ];
-          }
+  // modules/core/tree.js
+  function coreTree(head) {
+    var _rtree = new RBush();
+    var _bboxes = {};
+    var _segmentsRTree = new RBush();
+    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];
         });
-      }).filter(Boolean);
-      function getReference(id2) {
-        return function showReference(selection2) {
-          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append(`issues.incompatible_source.reference.${id2}`));
-        };
-      }
-    };
-    validation.type = type3;
-    return validation;
-  }
-
-  // modules/validations/maprules.js
-  function validationMaprules() {
-    var type3 = "maprules";
-    var validation = function checkMaprules(entity, graph) {
-      if (!services.maprules)
-        return [];
-      var rules = services.maprules.validationRules();
-      var issues = [];
-      for (var i2 = 0; i2 < rules.length; i2++) {
-        var rule = rules[i2];
-        rule.findIssues(entity, graph, issues);
-      }
-      return issues;
-    };
-    validation.type = type3;
-    return validation;
-  }
-
-  // modules/validations/mismatched_geometry.js
-  var import_fast_deep_equal4 = __toESM(require_fast_deep_equal());
-  function validationMismatchedGeometry() {
-    var type3 = "mismatched_geometry";
-    function tagSuggestingLineIsArea(entity) {
-      if (entity.type !== "way" || entity.isClosed())
-        return null;
-      var tagSuggestingArea = entity.tagSuggestingArea();
-      if (!tagSuggestingArea) {
-        return null;
-      }
-      var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, "line");
-      var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, "area");
-      if (asLine && asArea && asLine === asArea) {
-        return null;
+        delete _segmentsByWayId[entity.id];
       }
-      return tagSuggestingArea;
     }
-    function makeConnectEndpointsFixOnClick(way, graph) {
-      if (way.nodes.length < 3)
-        return null;
-      var nodes = graph.childNodes(way), testNodes;
-      var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc);
-      if (firstToLastDistanceMeters < 0.75) {
-        testNodes = nodes.slice();
-        testNodes.pop();
-        testNodes.push(testNodes[0]);
-        if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
-          return function(context) {
-            var way2 = context.entity(this.issue.entityIds[0]);
-            context.perform(
-              actionMergeNodes([way2.nodes[0], way2.nodes[way2.nodes.length - 1]], nodes[0].loc),
-              _t("issues.fix.connect_endpoints.annotation")
-            );
-          };
+    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);
         }
-      }
-      testNodes = nodes.slice();
-      testNodes.push(testNodes[0]);
-      if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
-        return function(context) {
-          var wayId = this.issue.entityIds[0];
-          var way2 = context.entity(wayId);
-          var nodeId = way2.nodes[0];
-          var index = way2.nodes.length;
-          context.perform(
-            actionAddVertex(wayId, nodeId, index),
-            _t("issues.fix.connect_endpoints.annotation")
-          );
-        };
-      }
+      });
+      if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
     }
-    function lineTaggedAsAreaIssue(entity) {
-      var tagSuggestingArea = tagSuggestingLineIsArea(entity);
-      if (!tagSuggestingArea)
-        return null;
-      return new validationIssue({
-        type: type3,
-        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),
-            tag: utilTagText({ tags: tagSuggestingArea })
-          }) : "";
-        },
-        reference: showReference,
-        entityIds: [entity.id],
-        hash: JSON.stringify(tagSuggestingArea),
-        dynamicFixes: function(context) {
-          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
-          }));
-          fixes.push(new validationIssueFix({
-            icon: "iD-operation-delete",
-            title: _t.append("issues.fix.remove_tag.title"),
-            onClick: function(context2) {
-              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];
-              }
-              context2.perform(
-                actionChangeTags(entityId, tags),
-                _t("issues.fix.remove_tag.annotation")
-              );
-            }
-          }));
-          return fixes;
+    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[relation.id]) return;
+        memo[relation.id] = true;
+        if (_bboxes[relation.id]) {
+          removeEntity(relation);
+          insertions[relation.id] = relation;
         }
+        updateParents(relation, insertions, memo);
       });
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.tag_suggests_area.reference"));
-      }
     }
-    function vertexPointIssue(entity, graph) {
-      if (entity.type !== "node")
-        return null;
-      if (Object.keys(entity.tags).length === 0)
-        return null;
-      if (entity.isOnAddressLine(graph))
-        return null;
-      var geometry = entity.geometry(graph);
-      var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
-      if (geometry === "point" && !allowedGeometries.point && allowedGeometries.vertex) {
-        return new validationIssue({
-          type: type3,
-          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)
-            }) : "";
-          },
-          reference: function showReference(selection2) {
-            selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.vertex_as_point.reference"));
-          },
-          entityIds: [entity.id]
+    tree.rebase = function(entities, force) {
+      var insertions = {};
+      for (var i3 = 0; i3 < entities.length; i3++) {
+        var entity = entities[i3];
+        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);
         });
-      } else if (geometry === "vertex" && !allowedGeometries.vertex && allowedGeometries.point) {
-        return new validationIssue({
-          type: type3,
-          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)
-            }) : "";
-          },
-          reference: function showReference(selection2) {
-            selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.point_as_vertex.reference"));
-          },
-          entityIds: [entity.id],
-          dynamicFixes: extractPointDynamicFixes
+      }
+      if (changed.geometry) {
+        diff.modified().forEach(function(entity) {
+          removeEntity(entity);
+          insertions[entity.id] = entity;
+          updateParents(entity, insertions, {});
         });
       }
-      return null;
+      if (changed.addition) {
+        diff.created().forEach(function(entity) {
+          insertions[entity.id] = entity;
+        });
+      }
+      loadEntities(Object.values(insertions));
     }
-    function otherMismatchIssue(entity, graph) {
-      if (!entity.hasInterestingTags())
-        return null;
-      if (entity.type !== "node" && entity.type !== "way")
-        return null;
-      if (entity.type === "node" && entity.isOnAddressLine(graph))
-        return null;
-      var sourceGeom = entity.geometry(graph);
-      var targetGeoms = entity.type === "way" ? ["point", "vertex"] : ["line", "area"];
-      if (sourceGeom === "area")
-        targetGeoms.unshift("line");
-      var asSource = _mainPresetIndex.match(entity, graph);
-      var targetGeom = targetGeoms.find((nodeGeom) => {
-        var asTarget = _mainPresetIndex.matchTags(entity.tags, nodeGeom);
-        if (!asSource || !asTarget || asSource === asTarget || (0, import_fast_deep_equal4.default)(asSource.tags, asTarget.tags))
-          return false;
-        if (asTarget.isFallback())
-          return false;
-        var primaryKey = Object.keys(asTarget.tags)[0];
-        if (primaryKey === "building")
-          return false;
-        if (asTarget.tags[primaryKey] === "*")
-          return false;
-        return asSource.isFallback() || asSource.tags[primaryKey] === "*";
+    tree.intersects = function(extent, graph) {
+      updateToGraph(graph);
+      return _rtree.search(extent.bbox()).map(function(bbox2) {
+        return graph.entity(bbox2.id);
       });
-      if (!targetGeom)
-        return null;
-      var subtype = targetGeom + "_as_" + sourceGeom;
-      if (targetGeom === "vertex")
-        targetGeom = "point";
-      if (sourceGeom === "vertex")
-        sourceGeom = "point";
-      var referenceId = targetGeom + "_as_" + sourceGeom;
-      var dynamicFixes;
-      if (targetGeom === "point") {
-        dynamicFixes = extractPointDynamicFixes;
-      } else if (sourceGeom === "area" && targetGeom === "line") {
-        dynamicFixes = lineToAreaDynamicFixes;
-      }
-      return new validationIssue({
-        type: type3,
-        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)
-          }) : "";
-        },
-        reference: function showReference(selection2) {
-          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.mismatched_geometry.reference"));
-        },
-        entityIds: [entity.id],
-        dynamicFixes
+    };
+    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);
     }
-    function lineToAreaDynamicFixes(context) {
-      var convertOnClick;
-      var entityId = this.entityIds[0];
-      var entity = context.entity(entityId);
-      var tags = Object.assign({}, entity.tags);
-      delete tags.area;
-      if (!osmTagSuggestingArea(tags)) {
-        convertOnClick = function(context2) {
-          var entityId2 = this.issue.entityIds[0];
-          var entity2 = context2.entity(entityId2);
-          var tags2 = Object.assign({}, entity2.tags);
-          if (tags2.area) {
-            delete tags2.area;
-          }
-          context2.perform(
-            actionChangeTags(entityId2, tags2),
-            _t("issues.fix.convert_to_line.annotation")
-          );
-        };
-      }
-      return [
-        new validationIssueFix({
-          icon: "iD-icon-line",
-          title: _t.append("issues.fix.convert_to_line.title"),
-          onClick: convertOnClick
-        })
-      ];
+    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);
     }
-    function extractPointDynamicFixes(context) {
-      var entityId = this.entityIds[0];
-      var extractOnClick = null;
-      if (!context.hasHiddenConnections(entityId)) {
-        extractOnClick = function(context2) {
-          var entityId2 = this.issue.entityIds[0];
-          var action = actionExtract(entityId2, context2.projection);
-          context2.perform(
-            action,
-            _t("operations.extract.annotation", { n: 1 })
-          );
-          context2.enter(modeSelect(context2, [action.getExtractedNodeID()]));
-        };
+    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();
       }
-      return [
-        new validationIssueFix({
-          icon: "iD-operation-extract",
-          title: _t.append("issues.fix.extract_point.title"),
-          onClick: extractOnClick
-        })
-      ];
     }
-    function unclosedMultipolygonPartIssues(entity, graph) {
-      if (entity.type !== "relation" || !entity.isMultipolygon() || entity.isDegenerate() || !entity.isComplete(graph))
-        return [];
-      var sequences = osmJoinWays(entity.members, graph);
-      var issues = [];
-      for (var i2 in sequences) {
-        var sequence = sequences[i2];
-        if (!sequence.nodes)
-          continue;
-        var firstNode = sequence.nodes[0];
-        var lastNode = sequence.nodes[sequence.nodes.length - 1];
-        if (firstNode === lastNode)
-          continue;
-        var issue = new validationIssue({
-          type: type3,
-          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)
-            }) : "";
-          },
-          reference: showReference,
-          loc: sequence.nodes[0].loc,
-          entityIds: [entity.id],
-          hash: sequence.map(function(way) {
-            return way.id;
-          }).join()
-        });
-        issues.push(issue);
-      }
-      return issues;
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.unclosed_multipolygon_part.reference"));
+    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();
       }
     }
-    var validation = function checkMismatchedGeometry(entity, graph) {
-      var vertexPoint = vertexPointIssue(entity, graph);
-      if (vertexPoint)
-        return [vertexPoint];
-      var lineAsArea = lineTaggedAsAreaIssue(entity);
-      if (lineAsArea)
-        return [lineAsArea];
-      var mismatch = otherMismatchIssue(entity, graph);
-      if (mismatch)
-        return [mismatch];
-      return unclosedMultipolygonPartIssues(entity, graph);
-    };
-    validation.type = type3;
-    return validation;
   }
 
-  // modules/validations/missing_role.js
-  function validationMissingRole() {
-    var type3 = "missing_role";
-    var validation = function checkMissingRole(entity, graph) {
-      var issues = [];
-      if (entity.type === "way") {
-        graph.parentRelations(entity).forEach(function(relation) {
-          if (!relation.isMultipolygon())
-            return;
-          var member = relation.memberById(entity.id);
-          if (member && isMissingRole(member)) {
-            issues.push(makeIssue(entity, relation, member));
-          }
-        });
-      } else if (entity.type === "relation" && entity.isMultipolygon()) {
-        entity.indexedMembers().forEach(function(member) {
-          var way = graph.hasEntity(member.id);
-          if (way && isMissingRole(member)) {
-            issues.push(makeIssue(way, entity, member));
-          }
-        });
-      }
-      return issues;
+  // 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;
     };
-    function isMissingRole(member) {
-      return !member.role || !member.role.trim().length;
-    }
-    function makeIssue(way, relation, member) {
-      return new validationIssue({
-        type: type3,
-        severity: "warning",
-        message: function(context) {
-          var member2 = context.hasEntity(this.entityIds[1]), relation2 = context.hasEntity(this.entityIds[0]);
-          return member2 && relation2 ? _t.append("issues.missing_role.message", {
-            member: utilDisplayLabel(member2, context.graph()),
-            relation: utilDisplayLabel(relation2, context.graph())
-          }) : "";
-        },
-        reference: showReference,
-        entityIds: [relation.id, way.id],
-        data: {
-          member
-        },
-        hash: member.index.toString(),
-        dynamicFixes: function() {
-          return [
-            makeAddRoleFix("inner"),
-            makeAddRoleFix("outer"),
-            new validationIssueFix({
-              icon: "iD-operation-delete",
-              title: _t.append("issues.fix.remove_from_relation.title"),
-              onClick: function(context) {
-                context.perform(
-                  actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index),
-                  _t("operations.delete_member.annotation", {
-                    n: 1
-                  })
-                );
-              }
-            })
-          ];
-        }
-      });
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.missing_role.multipolygon.reference"));
-      }
-    }
-    function makeAddRoleFix(role) {
-      return new validationIssueFix({
-        title: _t.append("issues.fix.set_as_" + role + ".title"),
-        onClick: function(context) {
-          var oldMember = this.issue.data.member;
-          var member = { id: this.issue.entityIds[1], type: oldMember.type, role };
-          context.perform(
-            actionChangeMember(this.issue.entityIds[0], member, oldMember.index),
-            _t("operations.change_role.annotation", {
-              n: 1
-            })
-          );
-        }
-      });
-    }
-    validation.type = type3;
-    return validation;
+    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/validations/missing_tag.js
-  function validationMissingTag(context) {
-    var type3 = "missing_tag";
-    function hasDescriptiveTags(entity, graph) {
-      var onlyAttributeKeys = ["description", "name", "note", "start_date"];
-      var entityDescriptiveKeys = Object.keys(entity.tags).filter(function(k) {
-        if (k === "area" || !osmIsInterestingTag(k))
-          return false;
-        return !onlyAttributeKeys.some(function(attributeKey) {
-          return k === attributeKey || k.indexOf(attributeKey + ":") === 0;
-        });
-      });
-      if (entity.type === "relation" && entityDescriptiveKeys.length === 1 && entity.tags.type === "multipolygon") {
-        return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
+  // modules/core/history.js
+  function coreHistory(context) {
+    var dispatch14 = 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, t2) {
+      actions = Array.prototype.slice.call(actions);
+      var annotation;
+      if (typeof actions[actions.length - 1] !== "function") {
+        annotation = actions.pop();
       }
-      return entityDescriptiveKeys.length > 0;
+      var graph = _stack[_index].graph;
+      for (var i3 = 0; i3 < actions.length; i3++) {
+        graph = actions[i3](graph, t2);
+      }
+      return {
+        graph,
+        annotation,
+        imageryUsed: _imageryUsed,
+        photoOverlaysUsed: _photoOverlaysUsed,
+        transform: context.projection.transform(),
+        selectedIDs: context.selectedIDs()
+      };
     }
-    function isUnknownRoad(entity) {
-      return entity.type === "way" && entity.tags.highway === "road";
+    function _perform(args, t2) {
+      var previous = _stack[_index].graph;
+      _stack = _stack.slice(0, _index + 1);
+      var actionResult = _act(args, t2);
+      _stack.push(actionResult);
+      _index++;
+      return change(previous);
     }
-    function isUntypedRelation(entity) {
-      return entity.type === "relation" && !entity.tags.type;
+    function _replace(args, t2) {
+      var previous = _stack[_index].graph;
+      var actionResult = _act(args, t2);
+      _stack[_index] = actionResult;
+      return change(previous);
     }
-    var validation = function checkMissingTag(entity, graph) {
-      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 (Object.keys(entity.tags).length === 0) {
-          subtype = "any";
-        } else if (!hasDescriptiveTags(entity, graph)) {
-          subtype = "descriptive";
-        } else if (isUntypedRelation(entity)) {
-          subtype = "relation_type";
-        }
+    function _overwrite(args, t2) {
+      var previous = _stack[_index].graph;
+      if (_index > 0) {
+        _index--;
+        _stack.pop();
       }
-      if (!subtype && isUnknownRoad(entity)) {
-        subtype = "highway_classification";
+      _stack = _stack.slice(0, _index + 1);
+      var actionResult = _act(args, t2);
+      _stack.push(actionResult);
+      _index++;
+      return change(previous);
+    }
+    function change(previous) {
+      var difference2 = coreDifference(previous, history.graph());
+      if (!_pausedGraph) {
+        dispatch14.call("change", this, difference2);
       }
-      if (!subtype)
-        return [];
-      var messageID = subtype === "highway_classification" ? "unknown_road" : "missing_tag." + subtype;
-      var referenceID = subtype === "highway_classification" ? "unknown_road" : "missing_tag";
-      var canDelete = entity.version === void 0 || entity.v !== void 0;
-      var severity = canDelete && subtype !== "highway_classification" ? "error" : "warning";
-      return [new validationIssue({
-        type: type3,
-        subtype,
-        severity,
-        message: function(context2) {
-          var entity2 = context2.hasEntity(this.entityIds[0]);
-          return entity2 ? _t.append("issues." + messageID + ".message", {
-            feature: utilDisplayLabel(entity2, context2.graph())
-          }) : "";
-        },
-        reference: showReference,
-        entityIds: [entity.id],
-        dynamicFixes: function(context2) {
-          var fixes = [];
-          var selectFixType = subtype === "highway_classification" ? "select_road_type" : "select_preset";
-          fixes.push(new validationIssueFix({
-            icon: "iD-icon-search",
-            title: _t.append("issues.fix." + selectFixType + ".title"),
-            onClick: function(context3) {
-              context3.ui().sidebar.showPresetList();
-            }
-          }));
-          var deleteOnClick;
-          var id2 = this.entityIds[0];
-          var operation = operationDelete(context2, [id2]);
-          var disabledReasonID = operation.disabled();
-          if (!disabledReasonID) {
-            deleteOnClick = function(context3) {
-              var id3 = this.issue.entityIds[0];
-              var operation2 = operationDelete(context3, [id3]);
-              if (!operation2.disabled()) {
-                operation2();
-              }
+      return difference2;
+    }
+    function getKey(n3) {
+      return "iD_" + window.location.origin + "_" + n3;
+    }
+    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);
+        dispatch14.call("merge", this, entities);
+      },
+      perform: function() {
+        select_default2(document).interrupt("history.perform");
+        var transitionable = false;
+        var action0 = arguments[0];
+        if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== "function") {
+          transitionable = !!action0.transitionable;
+        }
+        if (transitionable) {
+          var origArguments = arguments;
+          select_default2(document).transition("history.perform").duration(duration).ease(linear2).tween("history.tween", function() {
+            return function(t2) {
+              if (t2 < 1) _overwrite([action0], t2);
             };
+          }).on("start", function() {
+            _perform([action0], 0);
+          }).on("end interrupt", function() {
+            _overwrite(origArguments, 1);
+          });
+        } else {
+          return _perform(arguments);
+        }
+      },
+      replace: function() {
+        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);
+      },
+      pop: function(n3) {
+        select_default2(document).interrupt("history.perform");
+        var previous = _stack[_index].graph;
+        if (isNaN(+n3) || +n3 < 0) {
+          n3 = 1;
+        }
+        while (n3-- > 0 && _index > 0) {
+          _index--;
+          _stack.pop();
+        }
+        return change(previous);
+      },
+      // Back to the previous annotated state or _index = 0.
+      undo: function() {
+        select_default2(document).interrupt("history.perform");
+        var previousStack = _stack[_index];
+        var previous = previousStack.graph;
+        while (_index > 0) {
+          _index--;
+          if (_stack[_index].annotation) break;
+        }
+        dispatch14.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];
+        var previous = previousStack.graph;
+        var tryIndex = _index;
+        while (tryIndex < _stack.length - 1) {
+          tryIndex++;
+          if (_stack[tryIndex].annotation) {
+            _index = tryIndex;
+            dispatch14.call("redone", this, _stack[_index], previousStack);
+            break;
           }
-          fixes.push(
-            new validationIssueFix({
-              icon: "iD-operation-delete",
-              title: _t.append("issues.fix.delete_feature.title"),
-              disabledReason: disabledReasonID ? _t("operations.delete." + disabledReasonID + ".single") : void 0,
-              onClick: deleteOnClick
-            })
-          );
-          return fixes;
         }
-      })];
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues." + referenceID + ".reference"));
-      }
-    };
-    validation.type = type3;
-    return validation;
-  }
-
-  // modules/validations/outdated_tags.js
-  function validationOutdatedTags() {
-    const type3 = "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);
-      let preset = _mainPresetIndex.match(entity, graph);
-      let subtype = "deprecated_tags";
-      if (!preset)
-        return [];
-      if (!entity.hasInterestingTags())
-        return [];
-      if (preset.replacement) {
-        const newPreset = _mainPresetIndex.item(preset.replacement);
-        graph = actionChangePreset(entity.id, preset, newPreset, true)(graph);
-        entity = graph.entity(entity.id);
-        preset = newPreset;
-      }
-      if (_dataDeprecated) {
-        const deprecatedTags = entity.deprecatedTags(_dataDeprecated);
-        if (deprecatedTags.length) {
-          deprecatedTags.forEach((tag) => {
-            graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
+        return change(previous);
+      },
+      pauseChangeDispatch: function() {
+        if (!_pausedGraph) {
+          _pausedGraph = _stack[_index].graph;
+        }
+      },
+      resumeChangeDispatch: function() {
+        if (_pausedGraph) {
+          var previous = _pausedGraph;
+          _pausedGraph = null;
+          return change(previous);
+        }
+      },
+      undoAnnotation: function() {
+        var i3 = _index;
+        while (i3 >= 0) {
+          if (_stack[i3].annotation) return _stack[i3].annotation;
+          i3--;
+        }
+      },
+      redoAnnotation: function() {
+        var i3 = _index + 1;
+        while (i3 <= _stack.length - 1) {
+          if (_stack[i3].annotation) return _stack[i3].annotation;
+          i3++;
+        }
+      },
+      // Returns the entities from the active graph with bounding boxes
+      // overlapping the given `extent`.
+      intersects: function(extent) {
+        return _tree.intersects(extent, _stack[_index].graph);
+      },
+      difference: function() {
+        var base = _stack[0].graph;
+        var head = _stack[_index].graph;
+        return coreDifference(base, head);
+      },
+      changes: function(action) {
+        var base = _stack[0].graph;
+        var head = _stack[_index].graph;
+        if (action) {
+          head = action(head);
+        }
+        var difference2 = coreDifference(base, head);
+        return {
+          modified: difference2.modified(),
+          created: difference2.created(),
+          deleted: difference2.deleted()
+        };
+      },
+      hasChanges: function() {
+        return this.difference().length() > 0;
+      },
+      imageryUsed: function(sources) {
+        if (sources) {
+          _imageryUsed = sources;
+          return history;
+        } else {
+          var s2 = /* @__PURE__ */ new Set();
+          _stack.slice(1, _index + 1).forEach(function(state) {
+            state.imageryUsed.forEach(function(source) {
+              if (source !== "Custom") {
+                s2.add(source);
+              }
+            });
           });
-          entity = graph.entity(entity.id);
+          return Array.from(s2);
         }
-      }
-      let newTags = Object.assign({}, entity.tags);
-      if (preset.tags !== preset.addTags) {
-        Object.keys(preset.addTags).forEach((k) => {
-          if (!newTags[k]) {
-            if (preset.addTags[k] === "*") {
-              newTags[k] = "yes";
-            } else {
-              newTags[k] = preset.addTags[k];
+      },
+      photoOverlaysUsed: function(sources) {
+        if (sources) {
+          _photoOverlaysUsed = sources;
+          return history;
+        } else {
+          var s2 = /* @__PURE__ */ new Set();
+          _stack.slice(1, _index + 1).forEach(function(state) {
+            if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
+              state.photoOverlaysUsed.forEach(function(photoOverlay) {
+                s2.add(photoOverlay);
+              });
             }
-          }
+          });
+          return Array.from(s2);
+        }
+      },
+      // save the current history state
+      checkpoint: function(key) {
+        _checkpoints[key] = {
+          stack: _stack,
+          index: _index
+        };
+        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;
+          _index = _checkpoints[key].index;
+        } else {
+          _stack = [{ graph: coreGraph() }];
+          _index = 0;
+          _tree = coreTree(_stack[0].graph);
+          _checkpoints = {};
+        }
+        dispatch14.call("reset");
+        dispatch14.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 = {};
+        var graph = this.graph();
+        var baseEntities = {};
+        Object.values(graph.base().entities).forEach(function(entity) {
+          var copy2 = copyIntroEntity(entity);
+          baseEntities[copy2.id] = copy2;
         });
-      }
-      const nsi = services.nsi;
-      let waitingForNsi = false;
-      let nsiResult;
-      if (nsi) {
-        waitingForNsi = nsi.status() === "loading";
-        if (!waitingForNsi) {
-          const loc = entity.extent(graph).center();
-          nsiResult = nsi.upgradeTags(newTags, loc);
-          if (nsiResult) {
-            newTags = nsiResult.newTags;
-            subtype = "noncanonical_brand";
+        Object.keys(graph.entities).forEach(function(id2) {
+          var entity = graph.entities[id2];
+          if (entity) {
+            var copy2 = copyIntroEntity(entity);
+            baseEntities[copy2.id] = copy2;
+          } else {
+            delete baseEntities[id2];
           }
-        }
-      }
-      let issues = [];
-      issues.provisional = _waitingForDeprecated || waitingForNsi;
-      const tagDiff = utilTagDiff(oldTags, newTags);
-      if (!tagDiff.length)
-        return issues;
-      const isOnlyAddingTags = tagDiff.every((d) => d.type === "+");
-      let prefix = "";
-      if (nsiResult) {
-        prefix = "noncanonical_brand.";
-      } else if (subtype === "deprecated_tags" && isOnlyAddingTags) {
-        subtype = "incomplete_tags";
-        prefix = "incomplete.";
-      }
-      let autoArgs = subtype !== "noncanonical_brand" ? [doUpgrade, _t("issues.fix.upgrade_tags.annotation")] : null;
-      issues.push(new validationIssue({
-        type: type3,
-        subtype,
-        severity: "warning",
-        message: showMessage,
-        reference: showReference,
-        entityIds: [entity.id],
-        hash: utilHashcode(JSON.stringify(tagDiff)),
-        dynamicFixes: () => {
-          let fixes = [
-            new validationIssueFix({
-              autoArgs,
-              title: _t.append("issues.fix.upgrade_tags.title"),
-              onClick: (context) => {
-                context.perform(doUpgrade, _t("issues.fix.upgrade_tags.annotation"));
-              }
-            })
-          ];
-          const item = nsiResult && nsiResult.matched;
-          if (item) {
-            fixes.push(
-              new validationIssueFix({
-                title: _t.append("issues.fix.tag_as_not.title", { name: item.displayName }),
-                onClick: (context) => {
-                  context.perform(addNotTag, _t("issues.fix.tag_as_not.annotation"));
-                }
-              })
-            );
+        });
+        Object.values(baseEntities).forEach(function(entity) {
+          if (Array.isArray(entity.nodes)) {
+            entity.nodes = entity.nodes.map(function(node) {
+              return permIDs[node] || node;
+            });
           }
-          return fixes;
-        }
-      }));
-      return issues;
-      function doUpgrade(graph2) {
-        const currEntity = graph2.hasEntity(entity.id);
-        if (!currEntity)
-          return graph2;
-        let newTags2 = Object.assign({}, currEntity.tags);
-        tagDiff.forEach((diff) => {
-          if (diff.type === "-") {
-            delete newTags2[diff.key];
-          } else if (diff.type === "+") {
-            newTags2[diff.key] = diff.newVal;
+          if (Array.isArray(entity.members)) {
+            entity.members = entity.members.map(function(member) {
+              member.id = permIDs[member.id] || member.id;
+              return member;
+            });
           }
         });
-        return actionChangeTags(currEntity.id, newTags2)(graph2);
-      }
-      function addNotTag(graph2) {
-        const currEntity = graph2.hasEntity(entity.id);
-        if (!currEntity)
-          return graph2;
-        const item = nsiResult && nsiResult.matched;
-        if (!item)
-          return graph2;
-        let newTags2 = Object.assign({}, currEntity.tags);
-        const wd = item.mainTag;
-        const notwd = `not:${wd}`;
-        const qid = item.tags[wd];
-        newTags2[notwd] = qid;
-        if (newTags2[wd] === qid) {
-          const wp = item.mainTag.replace("wikidata", "wikipedia");
-          delete newTags2[wd];
-          delete newTags2[wp];
-        }
-        return actionChangeTags(currEntity.id, newTags2)(graph2);
-      }
-      function showMessage(context) {
-        const currEntity = context.hasEntity(entity.id);
-        if (!currEntity)
-          return "";
-        let messageID = `issues.outdated_tags.${prefix}message`;
-        if (subtype === "noncanonical_brand" && isOnlyAddingTags) {
-          messageID += "_incomplete";
+        return JSON.stringify({ dataIntroGraph: baseEntities });
+        function copyIntroEntity(source) {
+          var copy2 = utilObjectOmit(source, ["type", "user", "v", "version", "visible"]);
+          if (copy2.tags && !Object.keys(copy2.tags)) {
+            delete copy2.tags;
+          }
+          if (Array.isArray(copy2.loc)) {
+            copy2.loc[0] = +copy2.loc[0].toFixed(6);
+            copy2.loc[1] = +copy2.loc[1].toFixed(6);
+          }
+          var match = source.id.match(/([nrw])-\d*/);
+          if (match !== null) {
+            var nrw = match[1];
+            var permID;
+            do {
+              permID = nrw + ++nextID[nrw];
+            } while (baseEntities.hasOwnProperty(permID));
+            copy2.id = permIDs[source.id] = permID;
+          }
+          return copy2;
         }
-        return _t.append(messageID, {
-          feature: utilDisplayLabel(currEntity, context.graph(), true)
+      },
+      toJSON: function() {
+        if (!this.hasChanges()) return;
+        var allEntities = {};
+        var baseEntities = {};
+        var base = _stack[0];
+        var s2 = _stack.map(function(i3) {
+          var modified = [];
+          var deleted = [];
+          Object.keys(i3.graph.entities).forEach(function(id2) {
+            var entity = i3.graph.entities[id2];
+            if (entity) {
+              var key = osmEntity.key(entity);
+              allEntities[key] = entity;
+              modified.push(key);
+            } else {
+              deleted.push(id2);
+            }
+            if (id2 in base.graph.entities) {
+              baseEntities[id2] = base.graph.entities[id2];
+            }
+            if (entity && entity.nodes) {
+              entity.nodes.forEach(function(nodeID) {
+                if (nodeID in base.graph.entities) {
+                  baseEntities[nodeID] = base.graph.entities[nodeID];
+                }
+              });
+            }
+            var baseParents = base.graph._parentWays[id2];
+            if (baseParents) {
+              baseParents.forEach(function(parentID) {
+                if (parentID in base.graph.entities) {
+                  baseEntities[parentID] = base.graph.entities[parentID];
+                }
+              });
+            }
+          });
+          var x2 = {};
+          if (modified.length) x2.modified = modified;
+          if (deleted.length) x2.deleted = deleted;
+          if (i3.imageryUsed) x2.imageryUsed = i3.imageryUsed;
+          if (i3.photoOverlaysUsed) x2.photoOverlaysUsed = i3.photoOverlaysUsed;
+          if (i3.annotation) x2.annotation = i3.annotation;
+          if (i3.transform) x2.transform = i3.transform;
+          if (i3.selectedIDs) x2.selectedIDs = i3.selectedIDs;
+          return x2;
         });
-      }
-      function showReference(selection2) {
-        let enter = selection2.selectAll(".issue-reference").data([0]).enter();
-        enter.append("div").attr("class", "issue-reference").call(_t.append(`issues.outdated_tags.${prefix}reference`));
-        enter.append("strong").call(_t.append("issues.suggested"));
-        enter.append("table").attr("class", "tagDiff-table").selectAll(".tagDiff-row").data(tagDiff).enter().append("tr").attr("class", "tagDiff-row").append("td").attr("class", (d) => {
-          let klass = d.type === "+" ? "add" : "remove";
-          return `tagDiff-cell tagDiff-cell-${klass}`;
-        }).html((d) => d.display);
-      }
-    }
-    function oldMultipolygonIssues(entity, graph) {
-      let multipolygon, outerWay;
-      if (entity.type === "relation") {
-        outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
-        multipolygon = entity;
-      } else if (entity.type === "way") {
-        multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
-        outerWay = entity;
-      } else {
-        return [];
-      }
-      if (!multipolygon || !outerWay)
-        return [];
-      return [new validationIssue({
-        type: type3,
-        subtype: "old_multipolygon",
-        severity: "warning",
-        message: showMessage,
-        reference: showReference,
-        entityIds: [outerWay.id, multipolygon.id],
-        dynamicFixes: () => {
-          return [
-            new validationIssueFix({
-              autoArgs: [doUpgrade, _t("issues.fix.move_tags.annotation")],
-              title: _t.append("issues.fix.move_tags.title"),
-              onClick: (context) => {
-                context.perform(doUpgrade, _t("issues.fix.move_tags.annotation"));
+        return JSON.stringify({
+          version: 3,
+          entities: Object.values(allEntities),
+          baseEntities: Object.values(baseEntities),
+          stack: s2,
+          nextIDs: osmEntity.id.next,
+          index: _index,
+          // note the time the changes were saved
+          timestamp: (/* @__PURE__ */ new Date()).getTime()
+        });
+      },
+      fromJSON: function(json, loadChildNodes) {
+        var h2 = JSON.parse(json);
+        var loadComplete = true;
+        osmEntity.id.next = h2.nextIDs;
+        _index = h2.index;
+        if (h2.version === 2 || h2.version === 3) {
+          var allEntities = {};
+          h2.entities.forEach(function(entity) {
+            allEntities[osmEntity.key(entity)] = osmEntity(entity);
+          });
+          if (h2.version === 3) {
+            var baseEntities = h2.baseEntities.map(function(d2) {
+              return osmEntity(d2);
+            });
+            var stack = _stack.map(function(state) {
+              return state.graph;
+            });
+            _stack[0].graph.rebase(baseEntities, stack, true);
+            _tree.rebase(baseEntities, true);
+            if (loadChildNodes) {
+              var osm = context.connection();
+              var baseWays = baseEntities.filter(function(e3) {
+                return e3.type === "way";
+              });
+              var nodeIDs = baseWays.reduce(function(acc, way) {
+                return utilArrayUnion(acc, way.nodes);
+              }, []);
+              var missing = nodeIDs.filter(function(n3) {
+                return !_stack[0].graph.hasEntity(n3);
+              });
+              if (missing.length && osm) {
+                loadComplete = false;
+                context.map().redrawEnable(false);
+                var loading = uiLoading(context).blocking(true);
+                context.container().call(loading);
+                var childNodesLoaded = function(err, result) {
+                  if (!err) {
+                    var visibleGroups = utilArrayGroupBy(result.data, "visible");
+                    var visibles = visibleGroups.true || [];
+                    var invisibles = visibleGroups.false || [];
+                    if (visibles.length) {
+                      var visibleIDs = visibles.map(function(entity) {
+                        return entity.id;
+                      });
+                      var stack2 = _stack.map(function(state) {
+                        return state.graph;
+                      });
+                      missing = utilArrayDifference(missing, visibleIDs);
+                      _stack[0].graph.rebase(visibles, stack2, true);
+                      _tree.rebase(visibles, true);
+                    }
+                    invisibles.forEach(function(entity) {
+                      osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
+                    });
+                  }
+                  if (err || !missing.length) {
+                    loading.close();
+                    context.map().redrawEnable(true);
+                    dispatch14.call("change");
+                    dispatch14.call("restore", this);
+                  }
+                };
+                osm.loadMultiple(missing, childNodesLoaded);
               }
-            })
-          ];
+            }
+          }
+          _stack = h2.stack.map(function(d2) {
+            var entities = {}, entity;
+            if (d2.modified) {
+              d2.modified.forEach(function(key) {
+                entity = allEntities[key];
+                entities[entity.id] = entity;
+              });
+            }
+            if (d2.deleted) {
+              d2.deleted.forEach(function(id2) {
+                entities[id2] = void 0;
+              });
+            }
+            return {
+              graph: coreGraph(_stack[0].graph).load(entities),
+              annotation: d2.annotation,
+              imageryUsed: d2.imageryUsed,
+              photoOverlaysUsed: d2.photoOverlaysUsed,
+              transform: d2.transform,
+              selectedIDs: d2.selectedIDs
+            };
+          });
+        } else {
+          _stack = h2.stack.map(function(d2) {
+            var entities = {};
+            for (var i3 in d2.entities) {
+              var entity = d2.entities[i3];
+              entities[i3] = entity === "undefined" ? void 0 : osmEntity(entity);
+            }
+            d2.graph = coreGraph(_stack[0].graph).load(entities);
+            return d2;
+          });
         }
-      })];
-      function doUpgrade(graph2) {
-        let currMultipolygon = graph2.hasEntity(multipolygon.id);
-        let currOuterWay = graph2.hasEntity(outerWay.id);
-        if (!currMultipolygon || !currOuterWay)
-          return graph2;
-        currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
-        graph2 = graph2.replace(currMultipolygon);
-        return actionChangeTags(currOuterWay.id, {})(graph2);
-      }
-      function showMessage(context) {
-        let currMultipolygon = context.hasEntity(multipolygon.id);
-        if (!currMultipolygon)
-          return "";
-        return _t.append(
-          "issues.old_multipolygon.message",
-          { multipolygon: utilDisplayLabel(currMultipolygon, context.graph(), true) }
-        );
-      }
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.old_multipolygon.reference"));
-      }
-    }
-    let validation = function checkOutdatedTags(entity, graph) {
-      let issues = oldMultipolygonIssues(entity, graph);
-      if (!issues.length)
-        issues = oldTagIssues(entity, graph);
-      return issues;
+        var transform2 = _stack[_index].transform;
+        if (transform2) {
+          context.map().transformEase(transform2, 0);
+        }
+        if (loadComplete) {
+          dispatch14.call("change");
+          dispatch14.call("restore", this);
+        }
+        return history;
+      },
+      lock: function() {
+        return lock.lock();
+      },
+      unlock: function() {
+        lock.unlock();
+      },
+      save: function() {
+        if (lock.locked() && // don't overwrite existing, unresolved changes
+        !_hasUnresolvedRestorableChanges) {
+          const success = corePreferences(getKey("saved_history"), history.toJSON() || null);
+          if (!success) dispatch14.call("storage_error");
+        }
+        return history;
+      },
+      // delete the history version saved in localStorage
+      clearSaved: function() {
+        context.debouncedSave.cancel();
+        if (lock.locked()) {
+          _hasUnresolvedRestorableChanges = false;
+          corePreferences(getKey("saved_history"), null);
+          corePreferences("comment", null);
+          corePreferences("hashtags", null);
+          corePreferences("source", null);
+        }
+        return history;
+      },
+      savedHistoryJSON: function() {
+        return corePreferences(getKey("saved_history"));
+      },
+      hasRestorableChanges: function() {
+        return _hasUnresolvedRestorableChanges;
+      },
+      // load history from a version stored in localStorage
+      restore: function() {
+        if (lock.locked()) {
+          _hasUnresolvedRestorableChanges = false;
+          var json = this.savedHistoryJSON();
+          if (json) history.fromJSON(json, true);
+        }
+      },
+      _getKey: getKey
     };
-    validation.type = type3;
-    return validation;
+    history.reset();
+    return utilRebind(history, dispatch14, "on");
   }
 
-  // modules/validations/private_data.js
-  function validationPrivateData() {
-    var type3 = "private_data";
-    var privateBuildingValues = {
-      detached: true,
-      farm: true,
-      house: true,
-      houseboat: true,
-      residential: true,
-      semidetached_house: true,
-      static_caravan: true
-    };
-    var publicKeys = {
-      amenity: true,
-      craft: true,
-      historic: true,
-      leisure: true,
-      office: true,
-      shop: true,
-      tourism: true
-    };
-    var personalTags = {
-      "contact:email": true,
-      "contact:fax": true,
-      "contact:phone": true,
-      email: true,
-      fax: true,
-      phone: true
-    };
-    var validation = function checkPrivateData(entity) {
-      var tags = entity.tags;
-      if (!tags.building || !privateBuildingValues[tags.building])
-        return [];
-      var keepTags = {};
-      for (var k in tags) {
-        if (publicKeys[k])
-          return [];
-        if (!personalTags[k]) {
-          keepTags[k] = tags[k];
+  // modules/validations/index.js
+  var validations_exports = {};
+  __export(validations_exports, {
+    validationAlmostJunction: () => validationAlmostJunction,
+    validationCloseNodes: () => validationCloseNodes,
+    validationCrossingWays: () => validationCrossingWays,
+    validationDisconnectedWay: () => validationDisconnectedWay,
+    validationFormatting: () => validationFormatting,
+    validationHelpRequest: () => validationHelpRequest,
+    validationImpossibleOneway: () => validationImpossibleOneway,
+    validationIncompatibleSource: () => validationIncompatibleSource,
+    validationMaprules: () => validationMaprules,
+    validationMismatchedGeometry: () => validationMismatchedGeometry,
+    validationMissingRole: () => validationMissingRole,
+    validationMissingTag: () => validationMissingTag,
+    validationMutuallyExclusiveTags: () => validationMutuallyExclusiveTags,
+    validationOutdatedTags: () => validationOutdatedTags,
+    validationPrivateData: () => validationPrivateData,
+    validationSuspiciousName: () => validationSuspiciousName,
+    validationUnsquareWay: () => validationUnsquareWay
+  });
+
+  // modules/validations/almost_junction.js
+  function validationAlmostJunction(context) {
+    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;
+    const SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
+    function isHighway(entity) {
+      return entity.type === "way" && osmRoutableHighwayTagValues[entity.tags.highway];
+    }
+    function isTaggedAsNotContinuing(node) {
+      return node.tags.noexit === "yes" || node.tags.amenity === "parking_entrance" || node.tags.entrance && node.tags.entrance !== "no";
+    }
+    const validation = function checkAlmostJunction(entity, graph) {
+      if (!isHighway(entity)) return [];
+      if (entity.isDegenerate()) return [];
+      const tree = context.history().tree();
+      const extendableNodeInfos = findConnectableEndNodesByExtension(entity);
+      let issues = [];
+      extendableNodeInfos.forEach((extendableNodeInfo) => {
+        issues.push(new validationIssue({
+          type: type2,
+          subtype: "highway-highway",
+          severity: "warning",
+          message: function(context2) {
+            const entity1 = context2.hasEntity(this.entityIds[0]);
+            if (this.entityIds[0] === this.entityIds[2]) {
+              return entity1 ? _t.append("issues.almost_junction.self.message", {
+                feature: utilDisplayLabel(entity1, context2.graph())
+              }) : "";
+            } else {
+              const entity2 = context2.hasEntity(this.entityIds[2]);
+              return entity1 && entity2 ? _t.append("issues.almost_junction.message", {
+                feature: utilDisplayLabel(entity1, context2.graph()),
+                feature2: utilDisplayLabel(entity2, context2.graph())
+              }) : "";
+            }
+          },
+          reference: showReference,
+          entityIds: [
+            entity.id,
+            extendableNodeInfo.node.id,
+            extendableNodeInfo.wid
+          ],
+          loc: extendableNodeInfo.node.loc,
+          hash: JSON.stringify(extendableNodeInfo.node.loc),
+          data: {
+            midId: extendableNodeInfo.mid.id,
+            edge: extendableNodeInfo.edge,
+            cross_loc: extendableNodeInfo.cross_loc
+          },
+          dynamicFixes: makeFixes
+        }));
+      });
+      return issues;
+      function makeFixes(context2) {
+        let fixes = [new validationIssueFix({
+          icon: "iD-icon-abutment",
+          title: _t.append("issues.fix.connect_features.title"),
+          onClick: function(context3) {
+            const annotation = _t("issues.fix.connect_almost_junction.annotation");
+            const [, endNodeId, crossWayId] = this.issue.entityIds;
+            const midNode = context3.entity(this.issue.data.midId);
+            const endNode = context3.entity(endNodeId);
+            const crossWay = context3.entity(crossWayId);
+            const nearEndNodes = findNearbyEndNodes(endNode, crossWay);
+            if (nearEndNodes.length > 0) {
+              const collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
+              if (collinear) {
+                context3.perform(
+                  actionMergeNodes([collinear.id, endNode.id], collinear.loc),
+                  annotation
+                );
+                return;
+              }
+            }
+            const targetEdge = this.issue.data.edge;
+            const crossLoc = this.issue.data.cross_loc;
+            const edgeNodes = [context3.entity(targetEdge[0]), context3.entity(targetEdge[1])];
+            const closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc);
+            if (closestNodeInfo.distance < WELD_TH_METERS) {
+              context3.perform(
+                actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc),
+                annotation
+              );
+            } else {
+              context3.perform(
+                actionAddMidpoint({ loc: crossLoc, edge: targetEdge }, endNode),
+                annotation
+              );
+            }
+          }
+        })];
+        const node = context2.hasEntity(this.entityIds[1]);
+        if (node && !node.hasInterestingTags()) {
+          fixes.push(new validationIssueFix({
+            icon: "maki-barrier",
+            title: _t.append("issues.fix.tag_as_disconnected.title"),
+            onClick: function(context3) {
+              const nodeID = this.issue.entityIds[1];
+              const tags = Object.assign({}, context3.entity(nodeID).tags);
+              tags.noexit = "yes";
+              context3.perform(
+                actionChangeTags(nodeID, tags),
+                _t("issues.fix.tag_as_disconnected.annotation")
+              );
+            }
+          }));
         }
+        return fixes;
       }
-      var tagDiff = utilTagDiff(tags, keepTags);
-      if (!tagDiff.length)
-        return [];
-      var fixID = tagDiff.length === 1 ? "remove_tag" : "remove_tags";
-      return [new validationIssue({
-        type: type3,
-        severity: "warning",
-        message: showMessage,
-        reference: showReference,
-        entityIds: [entity.id],
-        dynamicFixes: function() {
-          return [
-            new validationIssueFix({
-              icon: "iD-operation-delete",
-              title: _t.append("issues.fix." + fixID + ".title"),
-              onClick: function(context) {
-                context.perform(doUpgrade, _t("issues.fix.remove_tag.annotation"));
-              }
-            })
-          ];
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.almost_junction.highway-highway.reference"));
+      }
+      function isExtendableCandidate(node, way) {
+        const osm = services.osm;
+        if (osm && !osm.isDataLoaded(node.loc)) {
+          return false;
         }
-      })];
-      function doUpgrade(graph) {
-        var currEntity = graph.hasEntity(entity.id);
-        if (!currEntity)
-          return graph;
-        var newTags = Object.assign({}, currEntity.tags);
-        tagDiff.forEach(function(diff) {
-          if (diff.type === "-") {
-            delete newTags[diff.key];
-          } else if (diff.type === "+") {
-            newTags[diff.key] = diff.newVal;
+        if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
+          return false;
+        }
+        let occurrences = 0;
+        for (const index in way.nodes) {
+          if (way.nodes[index] === node.id) {
+            occurrences += 1;
+            if (occurrences > 1) {
+              return false;
+            }
           }
+        }
+        return true;
+      }
+      function findConnectableEndNodesByExtension(way) {
+        let results = [];
+        if (way.isClosed()) return results;
+        let testNodes;
+        const indices = [0, way.nodes.length - 1];
+        indices.forEach((nodeIndex) => {
+          const nodeID = way.nodes[nodeIndex];
+          const node = graph.entity(nodeID);
+          if (!isExtendableCandidate(node, way)) return;
+          const connectionInfo = canConnectByExtend(way, nodeIndex);
+          if (!connectionInfo) return;
+          testNodes = graph.childNodes(way).slice();
+          testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc);
+          if (geoHasSelfIntersections(testNodes, nodeID)) return;
+          results.push(connectionInfo);
         });
-        return actionChangeTags(currEntity.id, newTags)(graph);
+        return results;
       }
-      function showMessage(context) {
-        var currEntity = context.hasEntity(this.entityIds[0]);
-        if (!currEntity)
-          return "";
-        return _t.append(
-          "issues.private_data.contact.message",
-          { feature: utilDisplayLabel(currEntity, context.graph()) }
-        );
+      function findNearbyEndNodes(node, way) {
+        return [
+          way.nodes[0],
+          way.nodes[way.nodes.length - 1]
+        ].map((d2) => graph.entity(d2)).filter((d2) => {
+          return d2.id !== node.id && geoSphericalDistance(node.loc, d2.loc) <= CLOSE_NODE_TH;
+        });
       }
-      function showReference(selection2) {
-        var enter = selection2.selectAll(".issue-reference").data([0]).enter();
-        enter.append("div").attr("class", "issue-reference").call(_t.append("issues.private_data.reference"));
-        enter.append("strong").call(_t.append("issues.suggested"));
-        enter.append("table").attr("class", "tagDiff-table").selectAll(".tagDiff-row").data(tagDiff).enter().append("tr").attr("class", "tagDiff-row").append("td").attr("class", function(d) {
-          var klass = d.type === "+" ? "add" : "remove";
-          return "tagDiff-cell tagDiff-cell-" + klass;
-        }).html(function(d) {
-          return d.display;
+      function findSmallJoinAngle(midNode, tipNode, endNodes) {
+        let joinTo;
+        let minAngle = Infinity;
+        endNodes.forEach((endNode) => {
+          const a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
+          const a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
+          const diff = Math.max(a1, a2) - Math.min(a1, a2);
+          if (diff < minAngle) {
+            joinTo = endNode;
+            minAngle = diff;
+          }
         });
+        if (minAngle <= SIG_ANGLE_TH) return joinTo;
+        return null;
+      }
+      function hasTag(tags, key) {
+        return tags[key] !== void 0 && tags[key] !== "no";
+      }
+      function canConnectWays(way, way2) {
+        if (way.id === way2.id) return true;
+        if ((hasTag(way.tags, "bridge") || hasTag(way2.tags, "bridge")) && !(hasTag(way.tags, "bridge") && hasTag(way2.tags, "bridge"))) return false;
+        if ((hasTag(way.tags, "tunnel") || hasTag(way2.tags, "tunnel")) && !(hasTag(way.tags, "tunnel") && hasTag(way2.tags, "tunnel"))) return false;
+        const layer1 = way.tags.layer || "0", layer2 = way2.tags.layer || "0";
+        if (layer1 !== layer2) return false;
+        const level1 = way.tags.level || "0", level2 = way2.tags.level || "0";
+        if (level1 !== level2) return false;
+        return true;
+      }
+      function canConnectByExtend(way, endNodeIdx) {
+        const tipNid = way.nodes[endNodeIdx];
+        const midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2];
+        const tipNode = graph.entity(tipNid);
+        const midNode = graph.entity(midNid);
+        const lon = tipNode.loc[0];
+        const lat = tipNode.loc[1];
+        const lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
+        const lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
+        const queryExtent = geoExtent([
+          [lon - lon_range, lat - lat_range],
+          [lon + lon_range, lat + lat_range]
+        ]);
+        const edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
+        const t2 = EXTEND_TH_METERS / edgeLen + 1;
+        const extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t2);
+        const segmentInfos = tree.waySegments(queryExtent, graph);
+        for (let i3 = 0; i3 < segmentInfos.length; i3++) {
+          let segmentInfo = segmentInfos[i3];
+          let way2 = graph.entity(segmentInfo.wayId);
+          if (!isHighway(way2)) continue;
+          if (!canConnectWays(way, way2)) continue;
+          let nAid = segmentInfo.nodes[0], nBid = segmentInfo.nodes[1];
+          if (nAid === tipNid || nBid === tipNid) continue;
+          let nA = graph.entity(nAid), nB = graph.entity(nBid);
+          let crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
+          if (crossLoc) {
+            return {
+              mid: midNode,
+              node: tipNode,
+              wid: way2.id,
+              edge: [nA.id, nB.id],
+              cross_loc: crossLoc
+            };
+          }
+        }
+        return null;
       }
     };
-    validation.type = type3;
+    validation.type = type2;
     return validation;
   }
 
-  // modules/validations/suspicious_name.js
-  function validationSuspiciousName() {
-    const type3 = "suspicious_name";
-    const keysToTestForGenericValues = [
-      "aerialway",
-      "aeroway",
-      "amenity",
-      "building",
-      "craft",
-      "highway",
-      "leisure",
-      "railway",
-      "man_made",
-      "office",
-      "shop",
-      "tourism",
-      "waterway"
-    ];
-    let _waitingForNsi = false;
-    function isGenericMatchInNsi(tags) {
-      const nsi = services.nsi;
-      if (nsi) {
-        _waitingForNsi = nsi.status() === "loading";
-        if (!_waitingForNsi) {
-          return nsi.isGenericName(tags);
+  // modules/validations/close_nodes.js
+  function validationCloseNodes(context) {
+    var type2 = "close_nodes";
+    var pointThresholdMeters = 0.2;
+    var validation = function(entity, graph) {
+      if (entity.type === "node") {
+        return getIssuesForNode(entity);
+      } else if (entity.type === "way") {
+        return getIssuesForWay(entity);
+      }
+      return [];
+      function getIssuesForNode(node) {
+        var parentWays = graph.parentWays(node);
+        if (parentWays.length) {
+          return getIssuesForVertex(node, parentWays);
+        } else {
+          return getIssuesForDetachedPoint(node);
         }
       }
-      return false;
-    }
-    function nameMatchesRawTag(lowercaseName, tags) {
-      for (let i2 = 0; i2 < keysToTestForGenericValues.length; i2++) {
-        let key = keysToTestForGenericValues[i2];
-        let val = tags[key];
-        if (val) {
-          val = val.toLowerCase();
-          if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, " ") === lowercaseName || val.replace(/\_/g, " ") === lowercaseName) {
-            return true;
+      function wayTypeFor(way) {
+        if (way.tags.boundary && way.tags.boundary !== "no") return "boundary";
+        if (way.tags.indoor && way.tags.indoor !== "no") return "indoor";
+        if (way.tags.building && way.tags.building !== "no" || way.tags["building:part"] && way.tags["building:part"] !== "no") return "building";
+        if (osmPathHighwayTagValues[way.tags.highway]) return "path";
+        var parentRelations = graph.parentRelations(way);
+        for (var i3 in parentRelations) {
+          var relation = parentRelations[i3];
+          if (relation.tags.type === "boundary") return "boundary";
+          if (relation.isMultipolygon()) {
+            if (relation.tags.indoor && relation.tags.indoor !== "no") return "indoor";
+            if (relation.tags.building && relation.tags.building !== "no" || relation.tags["building:part"] && relation.tags["building:part"] !== "no") return "building";
           }
         }
+        return "other";
       }
-      return false;
-    }
-    function isGenericName(name, tags) {
-      name = name.toLowerCase();
-      return nameMatchesRawTag(name, tags) || isGenericMatchInNsi(tags);
-    }
-    function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
-      return new validationIssue({
-        type: type3,
-        subtype: "generic_name",
-        severity: "warning",
-        message: function(context) {
-          let entity = context.hasEntity(this.entityIds[0]);
-          if (!entity)
-            return "";
-          let preset = _mainPresetIndex.match(entity, context.graph());
-          let langName = langCode && _mainLocalizer.languageName(langCode);
-          return _t.append(
-            "issues.generic_name.message" + (langName ? "_language" : ""),
-            { feature: preset.name(), name: genericName, language: langName }
-          );
-        },
-        reference: showReference,
-        entityIds: [entityId],
-        hash: `${nameKey}=${genericName}`,
-        dynamicFixes: function() {
-          return [
-            new validationIssueFix({
-              icon: "iD-operation-delete",
-              title: _t.append("issues.fix.remove_the_name.title"),
-              onClick: function(context) {
-                let entityId2 = this.issue.entityIds[0];
-                let entity = context.entity(entityId2);
-                let tags = Object.assign({}, entity.tags);
-                delete tags[nameKey];
-                context.perform(
-                  actionChangeTags(entityId2, tags),
-                  _t("issues.fix.remove_generic_name.annotation")
-                );
-              }
-            })
-          ];
+      function shouldCheckWay(way) {
+        if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
+        var bbox2 = way.extent(graph).bbox();
+        var hypotenuseMeters = geoSphericalDistance([bbox2.minX, bbox2.minY], [bbox2.maxX, bbox2.maxY]);
+        if (hypotenuseMeters < 1.5) return false;
+        return true;
+      }
+      function getIssuesForWay(way) {
+        if (!shouldCheckWay(way)) return [];
+        var issues = [], nodes = graph.childNodes(way);
+        for (var i3 = 0; i3 < nodes.length - 1; i3++) {
+          var node1 = nodes[i3];
+          var node2 = nodes[i3 + 1];
+          var issue = getWayIssueIfAny(node1, node2, way);
+          if (issue) issues.push(issue);
         }
-      });
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.generic_name.reference"));
+        return issues;
       }
-    }
-    function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
-      return new validationIssue({
-        type: type3,
-        subtype: "not_name",
-        severity: "warning",
-        message: function(context) {
-          const entity = context.hasEntity(this.entityIds[0]);
-          if (!entity)
-            return "";
-          const preset = _mainPresetIndex.match(entity, context.graph());
-          const langName = langCode && _mainLocalizer.languageName(langCode);
-          return _t.append(
-            "issues.incorrect_name.message" + (langName ? "_language" : ""),
-            { feature: preset.name(), name: incorrectName, language: langName }
-          );
-        },
-        reference: showReference,
-        entityIds: [entityId],
-        hash: `${nameKey}=${incorrectName}`,
-        dynamicFixes: function() {
-          return [
-            new validationIssueFix({
-              icon: "iD-operation-delete",
-              title: _t.append("issues.fix.remove_the_name.title"),
-              onClick: function(context) {
-                const entityId2 = this.issue.entityIds[0];
-                const entity = context.entity(entityId2);
-                let tags = Object.assign({}, entity.tags);
-                delete tags[nameKey];
-                context.perform(
-                  actionChangeTags(entityId2, tags),
-                  _t("issues.fix.remove_mistaken_name.annotation")
-                );
+      function getIssuesForVertex(node, parentWays) {
+        var issues = [];
+        function checkForCloseness(node1, node2, way) {
+          var issue = getWayIssueIfAny(node1, node2, way);
+          if (issue) issues.push(issue);
+        }
+        for (var i3 = 0; i3 < parentWays.length; i3++) {
+          var parentWay = parentWays[i3];
+          if (!shouldCheckWay(parentWay)) continue;
+          var lastIndex = parentWay.nodes.length - 1;
+          for (var j2 = 0; j2 < parentWay.nodes.length; j2++) {
+            if (j2 !== 0) {
+              if (parentWay.nodes[j2 - 1] === node.id) {
+                checkForCloseness(node, graph.entity(parentWay.nodes[j2]), parentWay);
               }
-            })
-          ];
+            }
+            if (j2 !== lastIndex) {
+              if (parentWay.nodes[j2 + 1] === node.id) {
+                checkForCloseness(graph.entity(parentWay.nodes[j2]), node, parentWay);
+              }
+            }
+          }
         }
-      });
-      function showReference(selection2) {
-        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.generic_name.reference"));
+        return issues;
       }
-    }
-    let validation = function checkGenericName(entity) {
-      const tags = entity.tags;
-      const hasWikidata = !!tags.wikidata || !!tags["brand:wikidata"] || !!tags["operator:wikidata"];
-      if (hasWikidata)
-        return [];
-      let issues = [];
-      const notNames2 = (tags["not:name"] || "").split(";");
-      for (let key in tags) {
-        const m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
-        if (!m)
-          continue;
-        const langCode = m.length >= 2 ? m[1] : null;
-        const value = tags[key];
-        if (notNames2.length) {
-          for (let i2 in notNames2) {
-            const notName = notNames2[i2];
-            if (notName && value === notName) {
-              issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
-              continue;
+      function thresholdMetersForWay(way) {
+        if (!shouldCheckWay(way)) return 0;
+        var wayType = wayTypeFor(way);
+        if (wayType === "boundary") return 0;
+        if (wayType === "indoor") return 0.01;
+        if (wayType === "building") return 0.05;
+        if (wayType === "path") return 0.1;
+        return 0.2;
+      }
+      function getIssuesForDetachedPoint(node) {
+        var issues = [];
+        var lon = node.loc[0];
+        var lat = node.loc[1];
+        var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
+        var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
+        var queryExtent = geoExtent([
+          [lon - lon_range, lat - lat_range],
+          [lon + lon_range, lat + lat_range]
+        ]);
+        var intersected = context.history().tree().intersects(queryExtent, graph);
+        for (var j2 = 0; j2 < intersected.length; j2++) {
+          var nearby = intersected[j2];
+          if (nearby.id === node.id) continue;
+          if (nearby.type !== "node" || nearby.geometry(graph) !== "point") continue;
+          if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
+            if ("memorial:type" in node.tags && "memorial:type" in nearby.tags && node.tags["memorial:type"] === "stolperstein" && nearby.tags["memorial:type"] === "stolperstein") continue;
+            if ("memorial" in node.tags && "memorial" in nearby.tags && node.tags.memorial === "stolperstein" && nearby.tags.memorial === "stolperstein") continue;
+            var zAxisKeys = { layer: true, level: true, "addr:housenumber": true, "addr:unit": true };
+            var zAxisDifferentiates = false;
+            for (var key in zAxisKeys) {
+              var nodeValue = node.tags[key] || "0";
+              var nearbyValue = nearby.tags[key] || "0";
+              if (nodeValue !== nearbyValue) {
+                zAxisDifferentiates = true;
+                break;
+              }
             }
+            if (zAxisDifferentiates) continue;
+            issues.push(new validationIssue({
+              type: type2,
+              subtype: "detached",
+              severity: "warning",
+              message: function(context2) {
+                var entity2 = context2.hasEntity(this.entityIds[0]), entity22 = context2.hasEntity(this.entityIds[1]);
+                return entity2 && entity22 ? _t.append("issues.close_nodes.detached.message", {
+                  feature: utilDisplayLabel(entity2, context2.graph()),
+                  feature2: utilDisplayLabel(entity22, context2.graph())
+                }) : "";
+              },
+              reference: showReference,
+              entityIds: [node.id, nearby.id],
+              dynamicFixes: function() {
+                return [
+                  new validationIssueFix({
+                    icon: "iD-operation-disconnect",
+                    title: _t.append("issues.fix.move_points_apart.title")
+                  }),
+                  new validationIssueFix({
+                    icon: "iD-icon-layers",
+                    title: _t.append("issues.fix.use_different_layers_or_levels.title")
+                  })
+                ];
+              }
+            }));
           }
         }
-        if (isGenericName(value, tags)) {
-          issues.provisional = _waitingForNsi;
-          issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
+        return issues;
+        function showReference(selection2) {
+          var referenceText = _t("issues.close_nodes.detached.reference");
+          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").html(referenceText);
         }
       }
-      return issues;
-    };
-    validation.type = type3;
-    return validation;
-  }
-
-  // modules/validations/unsquare_way.js
-  function validationUnsquareWay(context) {
-    var type3 = "unsquare_way";
-    var DEFAULT_DEG_THRESHOLD = 5;
-    var epsilon3 = 0.05;
-    var nodeThreshold = 10;
-    function isBuilding(entity, graph) {
-      if (entity.type !== "way" || entity.geometry(graph) !== "area")
-        return false;
-      return entity.tags.building && entity.tags.building !== "no";
-    }
-    var validation = function checkUnsquareWay(entity, graph) {
-      if (!isBuilding(entity, graph))
-        return [];
-      if (entity.tags.nonsquare === "yes")
-        return [];
-      var isClosed = entity.isClosed();
-      if (!isClosed)
-        return [];
-      var nodes = graph.childNodes(entity).slice();
-      if (nodes.length > nodeThreshold + 1)
-        return [];
-      var osm = services.osm;
-      if (!osm || nodes.some(function(node) {
-        return !osm.isDataLoaded(node.loc);
-      }))
-        return [];
-      var hasConnectedSquarableWays = nodes.some(function(node) {
-        return graph.parentWays(node).some(function(way) {
-          if (way.id === entity.id)
-            return false;
-          if (isBuilding(way, graph))
-            return true;
-          return graph.parentRelations(way).some(function(parentRelation) {
-            return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== "no";
+      function getWayIssueIfAny(node1, node2, way) {
+        if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
+          return null;
+        }
+        if (node1.loc !== node2.loc) {
+          var parentWays1 = graph.parentWays(node1);
+          var parentWays2 = new Set(graph.parentWays(node2));
+          var sharedWays = parentWays1.filter(function(parentWay) {
+            return parentWays2.has(parentWay);
+          });
+          var thresholds = sharedWays.map(function(parentWay) {
+            return thresholdMetersForWay(parentWay);
           });
+          var threshold = Math.min(...thresholds);
+          var distance = geoSphericalDistance(node1.loc, node2.loc);
+          if (distance > threshold) return null;
+        }
+        return new validationIssue({
+          type: type2,
+          subtype: "vertices",
+          severity: "warning",
+          message: function(context2) {
+            var entity2 = context2.hasEntity(this.entityIds[0]);
+            return entity2 ? _t.append("issues.close_nodes.message", { way: utilDisplayLabel(entity2, context2.graph()) }) : "";
+          },
+          reference: showReference,
+          entityIds: [way.id, node1.id, node2.id],
+          loc: node1.loc,
+          dynamicFixes: function() {
+            return [
+              new validationIssueFix({
+                icon: "iD-icon-plus",
+                title: _t.append("issues.fix.merge_points.title"),
+                onClick: function(context2) {
+                  var entityIds = this.issue.entityIds;
+                  var action = actionMergeNodes([entityIds[1], entityIds[2]]);
+                  context2.perform(action, _t("issues.fix.merge_close_vertices.annotation"));
+                }
+              }),
+              new validationIssueFix({
+                icon: "iD-operation-disconnect",
+                title: _t.append("issues.fix.move_points_apart.title")
+              })
+            ];
+          }
         });
-      });
-      if (hasConnectedSquarableWays)
-        return [];
-      var storedDegreeThreshold = corePreferences("validate-square-degrees");
-      var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
-      var points = nodes.map(function(node) {
-        return context.projection(node.loc);
-      });
-      if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon3, degreeThreshold, true))
-        return [];
-      var autoArgs;
-      if (!entity.tags.wikidata) {
-        var autoAction = actionOrthogonalize(entity.id, context.projection, void 0, degreeThreshold);
-        autoAction.transitionable = false;
-        autoArgs = [autoAction, _t("operations.orthogonalize.annotation.feature", { n: 1 })];
-      }
-      return [new validationIssue({
-        type: type3,
-        subtype: "building",
-        severity: "warning",
-        message: function(context2) {
-          var entity2 = context2.hasEntity(this.entityIds[0]);
-          return entity2 ? _t.append("issues.unsquare_way.message", {
-            feature: utilDisplayLabel(entity2, context2.graph())
-          }) : "";
-        },
-        reference: showReference,
-        entityIds: [entity.id],
-        hash: degreeThreshold,
-        dynamicFixes: function() {
-          return [
-            new validationIssueFix({
-              icon: "iD-operation-orthogonalize",
-              title: _t.append("issues.fix.square_feature.title"),
-              autoArgs,
-              onClick: function(context2, completionHandler) {
-                var entityId = this.issue.entityIds[0];
-                context2.perform(
-                  actionOrthogonalize(entityId, context2.projection, void 0, degreeThreshold),
-                  _t("operations.orthogonalize.annotation.feature", { n: 1 })
-                );
-                window.setTimeout(function() {
-                  completionHandler();
-                }, 175);
-              }
-            })
-          ];
+        function showReference(selection2) {
+          var referenceText = _t("issues.close_nodes.reference");
+          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").html(referenceText);
         }
-      })];
-      function showReference(selection2) {
-        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;
   }
 
-  // modules/core/validator.js
-  function coreValidator(context) {
-    let dispatch10 = dispatch_default("validated", "focusedIssue");
-    let validator = utilRebind({}, dispatch10, "on");
-    let _rules = {};
-    let _disabledRules = {};
-    let _ignoredIssueIDs = /* @__PURE__ */ new Set();
-    let _resolvedIssueIDs = /* @__PURE__ */ new Set();
-    let _baseCache = validationCache("base");
-    let _headCache = validationCache("head");
-    let _completeDiff = {};
-    let _headIsCurrent = false;
-    let _deferredRIC = {};
-    let _deferredST = /* @__PURE__ */ new Set();
-    let _headPromise;
-    const RETRY = 5e3;
-    const _errorOverrides = parseHashParam(context.initialHashParams.validationError);
-    const _warningOverrides = parseHashParam(context.initialHashParams.validationWarning);
-    const _disableOverrides = parseHashParam(context.initialHashParams.validationDisable);
-    function parseHashParam(param) {
-      let result = [];
-      let rules = (param || "").split(",");
-      rules.forEach((rule) => {
-        rule = rule.trim();
-        const parts = rule.split("/", 2);
-        const type3 = parts[0];
-        const subtype = parts[1] || "*";
-        if (!type3 || !subtype)
-          return;
-        result.push({ type: makeRegExp(type3), subtype: makeRegExp(subtype) });
-      });
-      return result;
-      function makeRegExp(str2) {
-        const escaped = str2.replace(/[-\/\\^$+?.()|[\]{}]/g, "\\$&").replace(/\*/g, ".*");
-        return new RegExp("^" + escaped + "$");
+  // modules/validations/crossing_ways.js
+  var import_lodash3 = __toESM(require_lodash());
+  function validationCrossingWays(context) {
+    var type2 = "crossing_ways";
+    function getFeatureWithFeatureTypeTagsForWay(way, graph) {
+      if (getFeatureType(way, graph) === null) {
+        var parentRels = graph.parentRelations(way);
+        for (var i3 = 0; i3 < parentRels.length; i3++) {
+          var rel = parentRels[i3];
+          if (getFeatureType(rel, graph) !== null) {
+            return rel;
+          }
+        }
       }
+      return way;
     }
-    validator.init = () => {
-      Object.values(validations_exports).forEach((validation) => {
-        if (typeof validation !== "function")
-          return;
-        const fn = validation(context);
-        const key = fn.type;
-        _rules[key] = fn;
-      });
-      let disabledRules = corePreferences("validate-disabledRules");
-      if (disabledRules) {
-        disabledRules.split(",").forEach((k) => _disabledRules[k] = true);
-      }
-    };
-    function reset(resetIgnored) {
-      _baseCache.queue = [];
-      _headCache.queue = [];
-      Object.keys(_deferredRIC).forEach((key) => {
-        window.cancelIdleCallback(key);
-        _deferredRIC[key]();
-      });
-      _deferredRIC = {};
-      _deferredST.forEach(window.clearTimeout);
-      _deferredST.clear();
-      if (resetIgnored)
-        _ignoredIssueIDs.clear();
-      _resolvedIssueIDs.clear();
-      _baseCache = validationCache("base");
-      _headCache = validationCache("head");
-      _completeDiff = {};
-      _headIsCurrent = false;
+    function hasTag(tags, key) {
+      return tags[key] !== void 0 && tags[key] !== "no";
     }
-    validator.reset = () => {
-      reset(true);
-    };
-    validator.resetIgnoredIssues = () => {
-      _ignoredIssueIDs.clear();
-      dispatch10.call("validated");
-    };
-    validator.revalidateUnsquare = () => {
-      revalidateUnsquare(_headCache);
-      revalidateUnsquare(_baseCache);
-      dispatch10.call("validated");
+    function taggedAsIndoor(tags) {
+      return hasTag(tags, "indoor") || hasTag(tags, "level") || tags.highway === "corridor";
+    }
+    function allowsBridge(featureType) {
+      return featureType === "highway" || featureType === "railway" || featureType === "waterway";
+    }
+    function allowsTunnel(featureType) {
+      return featureType === "highway" || featureType === "railway" || featureType === "waterway";
+    }
+    var ignoredBuildings = {
+      demolished: true,
+      dismantled: true,
+      proposed: true,
+      razed: true
     };
-    function revalidateUnsquare(cache) {
-      const checkUnsquareWay = _rules.unsquare_way;
-      if (!cache.graph || typeof checkUnsquareWay !== "function")
-        return;
-      cache.uncacheIssuesOfType("unsquare_way");
-      const buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), cache.graph).filter((entity) => entity.type === "way" && entity.tags.building && entity.tags.building !== "no");
-      buildings.forEach((entity) => {
-        const detected = checkUnsquareWay(entity, cache.graph);
-        if (!detected.length)
-          return;
-        cache.cacheIssues(detected);
-      });
+    function getFeatureType(entity, graph) {
+      var geometry = entity.geometry(graph);
+      if (geometry !== "line" && geometry !== "area") return null;
+      var tags = entity.tags;
+      if (hasTag(tags, "building") && !ignoredBuildings[tags.building]) return "building";
+      if (hasTag(tags, "highway") && osmRoutableHighwayTagValues[tags.highway]) return "highway";
+      if (geometry !== "line") return null;
+      if (hasTag(tags, "railway") && osmRailwayTrackTagValues[tags.railway]) return "railway";
+      if (hasTag(tags, "waterway") && osmFlowingWaterwayTagValues[tags.waterway]) return "waterway";
+      return null;
     }
-    validator.getIssues = (options2) => {
-      const opts = Object.assign({ what: "all", where: "all", includeIgnored: false, includeDisabledRules: false }, options2);
-      const view = context.map().extent();
-      let seen = /* @__PURE__ */ new Set();
-      let results = [];
-      if (_headCache.graph && _headCache.graph !== _baseCache.graph) {
-        Object.values(_headCache.issuesByIssueID).forEach((issue) => {
-          const userModified = (issue.entityIds || []).some((id2) => _completeDiff.hasOwnProperty(id2));
-          if (opts.what === "edited" && !userModified)
-            return;
-          if (!filter2(issue))
-            return;
-          seen.add(issue.id);
-          results.push(issue);
-        });
-      }
-      if (opts.what === "all") {
-        Object.values(_baseCache.issuesByIssueID).forEach((issue) => {
-          if (!filter2(issue))
-            return;
-          seen.add(issue.id);
-          results.push(issue);
-        });
-      }
-      return results;
-      function filter2(issue) {
-        if (!issue)
-          return false;
-        if (seen.has(issue.id))
-          return false;
-        if (_resolvedIssueIDs.has(issue.id))
-          return false;
-        if (opts.includeDisabledRules === "only" && !_disabledRules[issue.type])
-          return false;
-        if (!opts.includeDisabledRules && _disabledRules[issue.type])
-          return false;
-        if (opts.includeIgnored === "only" && !_ignoredIssueIDs.has(issue.id))
-          return false;
-        if (!opts.includeIgnored && _ignoredIssueIDs.has(issue.id))
-          return false;
-        if ((issue.entityIds || []).some((id2) => !context.hasEntity(id2)))
-          return false;
-        if (opts.where === "visible") {
-          const extent = issue.extent(context.graph());
-          if (!view.intersects(extent))
-            return false;
-        }
+    function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
+      var level1 = tags1.level || "0";
+      var level2 = tags2.level || "0";
+      if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
         return true;
       }
-    };
-    validator.getResolvedIssues = () => {
-      return Array.from(_resolvedIssueIDs).map((issueID) => _baseCache.issuesByIssueID[issueID]).filter(Boolean);
-    };
-    validator.focusIssue = (issue) => {
-      const graph = context.graph();
-      let selectID;
-      let focusCenter;
-      const issueExtent = issue.extent(graph);
-      if (issueExtent) {
-        focusCenter = issueExtent.center();
-      }
-      if (issue.entityIds && issue.entityIds.length) {
-        selectID = issue.entityIds[0];
-        if (selectID && selectID.charAt(0) === "r") {
-          const ids = utilEntityAndDeepMemberIDs([selectID], graph);
-          let nodeID = ids.find((id2) => id2.charAt(0) === "n" && graph.hasEntity(id2));
-          if (!nodeID) {
-            const wayID = ids.find((id2) => id2.charAt(0) === "w" && graph.hasEntity(id2));
-            if (wayID) {
-              nodeID = graph.entity(wayID).first();
-            }
-          }
-          if (nodeID) {
-            focusCenter = graph.entity(nodeID).loc;
-          }
-        }
-      }
-      if (focusCenter) {
-        const setZoom = Math.max(context.map().zoom(), 19);
-        context.map().unobscuredCenterZoomEase(focusCenter, setZoom);
-      }
-      if (selectID) {
-        window.setTimeout(() => {
-          context.enter(modeSelect(context, [selectID]));
-          dispatch10.call("focusedIssue", this, issue);
-        }, 250);
+      var layer1 = tags1.layer || "0";
+      var layer2 = tags2.layer || "0";
+      if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
+        if (hasTag(tags1, "bridge") && !hasTag(tags2, "bridge")) return true;
+        if (!hasTag(tags1, "bridge") && hasTag(tags2, "bridge")) return true;
+        if (hasTag(tags1, "bridge") && hasTag(tags2, "bridge") && layer1 !== layer2) return true;
+      } else if (allowsBridge(featureType1) && hasTag(tags1, "bridge")) return true;
+      else if (allowsBridge(featureType2) && hasTag(tags2, "bridge")) return true;
+      if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
+        if (hasTag(tags1, "tunnel") && !hasTag(tags2, "tunnel")) return true;
+        if (!hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel")) return true;
+        if (hasTag(tags1, "tunnel") && hasTag(tags2, "tunnel") && layer1 !== layer2) return true;
+      } else if (allowsTunnel(featureType1) && hasTag(tags1, "tunnel")) return true;
+      else if (allowsTunnel(featureType2) && hasTag(tags2, "tunnel")) return true;
+      if (featureType1 === "waterway" && featureType2 === "highway" && tags2.man_made === "pier") return true;
+      if (featureType2 === "waterway" && featureType1 === "highway" && tags1.man_made === "pier") return true;
+      if (featureType1 === "building" || featureType2 === "building" || taggedAsIndoor(tags1) || taggedAsIndoor(tags2)) {
+        if (layer1 !== layer2) return true;
       }
+      return false;
+    }
+    var highwaysDisallowingFords = {
+      motorway: true,
+      motorway_link: true,
+      trunk: true,
+      trunk_link: true,
+      primary: true,
+      primary_link: true,
+      secondary: true,
+      secondary_link: true
     };
-    validator.getIssuesBySeverity = (options2) => {
-      let groups = utilArrayGroupBy(validator.getIssues(options2), "severity");
-      groups.error = groups.error || [];
-      groups.warning = groups.warning || [];
-      return groups;
-    };
-    validator.getSharedEntityIssues = (entityIDs, options2) => {
-      const orderedIssueTypes = [
-        "missing_tag",
-        "missing_role",
-        "outdated_tags",
-        "mismatched_geometry",
-        "crossing_ways",
-        "almost_junction",
-        "disconnected_way",
-        "impossible_oneway"
-      ];
-      const allIssues = validator.getIssues(options2);
-      const forEntityIDs = new Set(entityIDs);
-      return allIssues.filter((issue) => (issue.entityIds || []).some((entityID) => forEntityIDs.has(entityID))).sort((issue1, issue2) => {
-        if (issue1.type === issue2.type) {
-          return issue1.id < issue2.id ? -1 : 1;
-        }
-        const index1 = orderedIssueTypes.indexOf(issue1.type);
-        const index2 = orderedIssueTypes.indexOf(issue2.type);
-        if (index1 !== -1 && index2 !== -1) {
-          return index1 - index2;
-        } else if (index1 === -1 && index2 === -1) {
-          return issue1.type < issue2.type ? -1 : 1;
-        } else {
-          return index1 !== -1 ? -1 : 1;
-        }
-      });
-    };
-    validator.getEntityIssues = (entityID, options2) => {
-      return validator.getSharedEntityIssues([entityID], options2);
-    };
-    validator.getRuleKeys = () => {
-      return Object.keys(_rules);
-    };
-    validator.isRuleEnabled = (key) => {
-      return !_disabledRules[key];
-    };
-    validator.toggleRule = (key) => {
-      if (_disabledRules[key]) {
-        delete _disabledRules[key];
-      } else {
-        _disabledRules[key] = true;
-      }
-      corePreferences("validate-disabledRules", Object.keys(_disabledRules).join(","));
-      validator.validate();
-    };
-    validator.disableRules = (keys) => {
-      _disabledRules = {};
-      keys.forEach((k) => _disabledRules[k] = true);
-      corePreferences("validate-disabledRules", Object.keys(_disabledRules).join(","));
-      validator.validate();
-    };
-    validator.ignoreIssue = (issueID) => {
-      _ignoredIssueIDs.add(issueID);
-    };
-    validator.validate = () => {
-      const baseGraph = context.history().base();
-      if (!_headCache.graph)
-        _headCache.graph = baseGraph;
-      if (!_baseCache.graph)
-        _baseCache.graph = baseGraph;
-      const prevGraph = _headCache.graph;
-      const currGraph = context.graph();
-      if (currGraph === prevGraph) {
-        _headIsCurrent = true;
-        dispatch10.call("validated");
-        return Promise.resolve();
-      }
-      if (_headPromise) {
-        _headIsCurrent = false;
-        return _headPromise;
-      }
-      _headCache.graph = currGraph;
-      _completeDiff = context.history().difference().complete();
-      const incrementalDiff = coreDifference(prevGraph, currGraph);
-      let entityIDs = Object.keys(incrementalDiff.complete());
-      entityIDs = _headCache.withAllRelatedEntities(entityIDs);
-      if (!entityIDs.size) {
-        dispatch10.call("validated");
-        return Promise.resolve();
-      }
-      _headPromise = validateEntitiesAsync(entityIDs, _headCache).then(() => updateResolvedIssues(entityIDs)).then(() => dispatch10.call("validated")).catch(() => {
-      }).then(() => {
-        _headPromise = null;
-        if (!_headIsCurrent) {
-          validator.validate();
-        }
-      });
-      return _headPromise;
-    };
-    context.history().on("restore.validator", validator.validate).on("undone.validator", validator.validate).on("redone.validator", validator.validate).on("reset.validator", () => {
-      reset(false);
-      validator.validate();
-    });
-    context.on("exit.validator", validator.validate);
-    context.history().on("merge.validator", (entities) => {
-      if (!entities)
-        return;
-      const baseGraph = context.history().base();
-      if (!_headCache.graph)
-        _headCache.graph = baseGraph;
-      if (!_baseCache.graph)
-        _baseCache.graph = baseGraph;
-      let entityIDs = entities.map((entity) => entity.id);
-      entityIDs = _baseCache.withAllRelatedEntities(entityIDs);
-      validateEntitiesAsync(entityIDs, _baseCache);
-    });
-    function validateEntity(entity, graph) {
-      let result = { issues: [], provisional: false };
-      Object.keys(_rules).forEach(runValidation);
-      return result;
-      function runValidation(key) {
-        const fn = _rules[key];
-        if (typeof fn !== "function") {
-          console.error("no such validation rule = " + key);
-          return;
-        }
-        let detected = fn(entity, graph);
-        if (detected.provisional) {
-          result.provisional = true;
-        }
-        detected = detected.filter(applySeverityOverrides);
-        result.issues = result.issues.concat(detected);
-        function applySeverityOverrides(issue) {
-          const type3 = 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)) {
-              issue.severity = "error";
-              return true;
+    function tagsForConnectionNodeIfAllowed(entity1, entity2, graph, lessLikelyTags) {
+      var featureType1 = getFeatureType(entity1, graph);
+      var featureType2 = getFeatureType(entity2, graph);
+      var geometry1 = entity1.geometry(graph);
+      var geometry2 = entity2.geometry(graph);
+      var bothLines = geometry1 === "line" && geometry2 === "line";
+      if (featureType1 === featureType2) {
+        if (featureType1 === "highway") {
+          var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
+          var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
+          if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
+            var roadFeature = entity1IsPath ? entity2 : entity1;
+            var pathFeature = entity1IsPath ? entity1 : entity2;
+            if (roadFeature.tags.highway === "track") {
+              return {};
+            }
+            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" } : {};
           }
-          for (i2 = 0; i2 < _warningOverrides.length; i2++) {
-            if (_warningOverrides[i2].type.test(type3) && _warningOverrides[i2].subtype.test(subtype)) {
-              issue.severity = "warning";
-              return true;
+          return {};
+        }
+        if (featureType1 === "waterway") return {};
+        if (featureType1 === "railway") return {};
+      } else {
+        var featureTypes = [featureType1, featureType2];
+        if (featureTypes.indexOf("highway") !== -1) {
+          if (featureTypes.indexOf("railway") !== -1) {
+            if (!bothLines) return {};
+            var isTram = entity1.tags.railway === "tram" || entity2.tags.railway === "tram";
+            if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
+              if (isTram) return { railway: "tram_crossing" };
+              return { railway: "crossing" };
+            } else {
+              if (isTram) return { railway: "tram_level_crossing" };
+              return { railway: "level_crossing" };
             }
           }
-          for (i2 = 0; i2 < _disableOverrides.length; i2++) {
-            if (_disableOverrides[i2].type.test(type3) && _disableOverrides[i2].subtype.test(subtype)) {
-              return false;
+          if (featureTypes.indexOf("waterway") !== -1) {
+            if (hasTag(entity1.tags, "tunnel") && hasTag(entity2.tags, "tunnel")) return null;
+            if (hasTag(entity1.tags, "bridge") && hasTag(entity2.tags, "bridge")) return null;
+            if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
+              return null;
             }
+            return bothLines ? { ford: "yes" } : {};
           }
-          return true;
         }
       }
+      return null;
     }
-    function updateResolvedIssues(entityIDs) {
-      entityIDs.forEach((entityID) => {
-        const baseIssues = _baseCache.issuesByEntityID[entityID];
-        if (!baseIssues)
-          return;
-        baseIssues.forEach((issueID) => {
-          const issue = _baseCache.issuesByIssueID[issueID];
-          const userModified = (issue.entityIds || []).some((id2) => _completeDiff.hasOwnProperty(id2));
-          if (userModified && !_headCache.issuesByIssueID[issueID]) {
-            _resolvedIssueIDs.add(issueID);
-          } else {
-            _resolvedIssueIDs.delete(issueID);
+    function findCrossingsByWay(way1, graph, tree) {
+      var edgeCrossInfos = [];
+      if (way1.type !== "way") return edgeCrossInfos;
+      var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
+      var way1FeatureType = getFeatureType(taggedFeature1, graph);
+      if (way1FeatureType === null) return edgeCrossInfos;
+      var checkedSingleCrossingWays = {};
+      var i3, j2;
+      var extent;
+      var n1, n22, nA, nB, nAId, nBId;
+      var segment1, segment2;
+      var oneOnly;
+      var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
+      var way1Nodes = graph.childNodes(way1);
+      var comparedWays = {};
+      for (i3 = 0; i3 < way1Nodes.length - 1; i3++) {
+        n1 = way1Nodes[i3];
+        n22 = way1Nodes[i3 + 1];
+        extent = geoExtent([
+          [
+            Math.min(n1.loc[0], n22.loc[0]),
+            Math.min(n1.loc[1], n22.loc[1])
+          ],
+          [
+            Math.max(n1.loc[0], n22.loc[0]),
+            Math.max(n1.loc[1], n22.loc[1])
+          ]
+        ]);
+        segmentInfos = tree.waySegments(extent, graph);
+        for (j2 = 0; j2 < segmentInfos.length; j2++) {
+          segment2Info = segmentInfos[j2];
+          if (segment2Info.wayId === way1.id) continue;
+          if (checkedSingleCrossingWays[segment2Info.wayId]) continue;
+          comparedWays[segment2Info.wayId] = true;
+          way2 = graph.hasEntity(segment2Info.wayId);
+          if (!way2) continue;
+          taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph);
+          way2FeatureType = getFeatureType(taggedFeature2, graph);
+          if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
+            continue;
           }
-        });
-      });
-    }
-    function validateEntitiesAsync(entityIDs, cache) {
-      const jobs = Array.from(entityIDs).map((entityID) => {
-        if (cache.queuedEntityIDs.has(entityID))
-          return null;
-        cache.queuedEntityIDs.add(entityID);
-        cache.uncacheEntityID(entityID);
-        return () => {
-          cache.queuedEntityIDs.delete(entityID);
-          const graph = cache.graph;
-          if (!graph)
-            return;
-          const entity = graph.hasEntity(entityID);
-          if (!entity)
-            return;
-          const result = validateEntity(entity, graph);
-          if (result.provisional) {
-            cache.provisionalEntityIDs.add(entityID);
+          oneOnly = way1FeatureType === "building" || way2FeatureType === "building";
+          nAId = segment2Info.nodes[0];
+          nBId = segment2Info.nodes[1];
+          if (nAId === n1.id || nAId === n22.id || nBId === n1.id || nBId === n22.id) {
+            continue;
           }
-          cache.cacheIssues(result.issues);
-        };
-      }).filter(Boolean);
-      cache.queue = cache.queue.concat(utilArrayChunk(jobs, 100));
-      if (cache.queuePromise)
-        return cache.queuePromise;
-      cache.queuePromise = processQueue(cache).then(() => revalidateProvisionalEntities(cache)).catch(() => {
-      }).finally(() => cache.queuePromise = null);
-      return cache.queuePromise;
-    }
-    function revalidateProvisionalEntities(cache) {
-      if (!cache.provisionalEntityIDs.size)
-        return;
-      const handle = window.setTimeout(() => {
-        _deferredST.delete(handle);
-        if (!cache.provisionalEntityIDs.size)
-          return;
-        validateEntitiesAsync(Array.from(cache.provisionalEntityIDs), cache);
-      }, RETRY);
-      _deferredST.add(handle);
+          nA = graph.hasEntity(nAId);
+          if (!nA) continue;
+          nB = graph.hasEntity(nBId);
+          if (!nB) continue;
+          segment1 = [n1.loc, n22.loc];
+          segment2 = [nA.loc, nB.loc];
+          var point = geoLineIntersection(segment1, segment2);
+          if (point) {
+            edgeCrossInfos.push({
+              wayInfos: [
+                {
+                  way: way1,
+                  featureType: way1FeatureType,
+                  edge: [n1.id, n22.id]
+                },
+                {
+                  way: way2,
+                  featureType: way2FeatureType,
+                  edge: [nA.id, nB.id]
+                }
+              ],
+              crossPoint: point
+            });
+            if (oneOnly) {
+              checkedSingleCrossingWays[way2.id] = true;
+              break;
+            }
+          }
+        }
+      }
+      return edgeCrossInfos;
     }
-    function processQueue(cache) {
-      if (!cache.queue.length)
-        return Promise.resolve();
-      const chunk = cache.queue.pop();
-      return new Promise((resolvePromise, rejectPromise) => {
-        const handle = window.requestIdleCallback(() => {
-          delete _deferredRIC[handle];
-          chunk.forEach((job) => job());
-          resolvePromise();
-        });
-        _deferredRIC[handle] = rejectPromise;
-      }).then(() => {
-        if (cache.queue.length % 25 === 0)
-          dispatch10.call("validated");
-      }).then(() => processQueue(cache));
+    function waysToCheck(entity, graph) {
+      var featureType = getFeatureType(entity, graph);
+      if (!featureType) return [];
+      if (entity.type === "way") {
+        return [entity];
+      } else if (entity.type === "relation") {
+        return entity.members.reduce(function(array2, member) {
+          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);
+            }
+          }
+          return array2;
+        }, []);
+      }
+      return [];
     }
-    return validator;
-  }
-  function validationCache(which) {
-    let cache = {
-      which,
-      graph: null,
-      queue: [],
-      queuePromise: null,
-      queuedEntityIDs: /* @__PURE__ */ new Set(),
-      provisionalEntityIDs: /* @__PURE__ */ new Set(),
-      issuesByIssueID: {},
-      issuesByEntityID: {}
-    };
-    cache.cacheIssue = (issue) => {
-      (issue.entityIds || []).forEach((entityID) => {
-        if (!cache.issuesByEntityID[entityID]) {
-          cache.issuesByEntityID[entityID] = /* @__PURE__ */ new Set();
+    var validation = function checkCrossingWays(entity, graph) {
+      var tree = context.history().tree();
+      var ways = waysToCheck(entity, graph);
+      var issues = [];
+      var wayIndex, crossingIndex, crossings;
+      for (wayIndex in ways) {
+        crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
+        for (crossingIndex in crossings) {
+          issues.push(createIssue(crossings[crossingIndex], graph));
         }
-        cache.issuesByEntityID[entityID].add(issue.id);
-      });
-      cache.issuesByIssueID[issue.id] = issue;
+      }
+      return issues;
     };
-    cache.uncacheIssue = (issue) => {
-      (issue.entityIds || []).forEach((entityID) => {
-        if (cache.issuesByEntityID[entityID]) {
-          cache.issuesByEntityID[entityID].delete(issue.id);
+    function createIssue(crossing, graph) {
+      crossing.wayInfos.sort(function(way1Info, way2Info) {
+        var type1 = way1Info.featureType;
+        var type22 = way2Info.featureType;
+        if (type1 === type22) {
+          return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
+        } else if (type1 === "waterway") {
+          return true;
+        } else if (type22 === "waterway") {
+          return false;
         }
+        return type1 < type22;
       });
-      delete cache.issuesByIssueID[issue.id];
-    };
-    cache.cacheIssues = (issues) => {
-      issues.forEach(cache.cacheIssue);
-    };
-    cache.uncacheIssues = (issues) => {
-      issues.forEach(cache.uncacheIssue);
-    };
-    cache.uncacheIssuesOfType = (type3) => {
-      const issuesOfType = Object.values(cache.issuesByIssueID).filter((issue) => issue.type === type3);
-      cache.uncacheIssues(issuesOfType);
-    };
-    cache.uncacheEntityID = (entityID) => {
-      const entityIssueIDs = cache.issuesByEntityID[entityID];
-      if (entityIssueIDs) {
-        entityIssueIDs.forEach((issueID) => {
-          const issue = cache.issuesByIssueID[issueID];
-          if (issue) {
-            cache.uncacheIssue(issue);
-          } else {
-            delete cache.issuesByIssueID[issueID];
-          }
-        });
+      var entities = crossing.wayInfos.map(function(wayInfo) {
+        return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
+      });
+      var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
+      var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
+      var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
+      var featureType1 = crossing.wayInfos[0].featureType;
+      var featureType2 = crossing.wayInfos[1].featureType;
+      var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
+      var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, "tunnel") && allowsTunnel(featureType2) && hasTag(entities[1].tags, "tunnel");
+      var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, "bridge") && allowsBridge(featureType2) && hasTag(entities[1].tags, "bridge");
+      var subtype = [featureType1, featureType2].sort().join("-");
+      var crossingTypeID = subtype;
+      if (isCrossingIndoors) {
+        crossingTypeID = "indoor-indoor";
+      } else if (isCrossingTunnels) {
+        crossingTypeID = "tunnel-tunnel";
+      } else if (isCrossingBridges) {
+        crossingTypeID = "bridge-bridge";
       }
-      delete cache.issuesByEntityID[entityID];
-      cache.provisionalEntityIDs.delete(entityID);
-    };
-    cache.withAllRelatedEntities = (entityIDs) => {
-      let result = /* @__PURE__ */ new Set();
-      (entityIDs || []).forEach((entityID) => {
-        result.add(entityID);
-        const entityIssueIDs = cache.issuesByEntityID[entityID];
-        if (entityIssueIDs) {
-          entityIssueIDs.forEach((issueID) => {
-            const issue = cache.issuesByIssueID[issueID];
-            if (issue) {
-              (issue.entityIds || []).forEach((relatedID) => result.add(relatedID));
-            } else {
-              delete cache.issuesByIssueID[issueID];
+      if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
+        crossingTypeID += "_connectable";
+      }
+      var uniqueID = crossing.crossPoint[0].toFixed(4) + "," + crossing.crossPoint[1].toFixed(4);
+      return new validationIssue({
+        type: type2,
+        subtype,
+        severity: "warning",
+        message: function(context2) {
+          var graph2 = context2.graph();
+          var entity1 = graph2.hasEntity(this.entityIds[0]), entity2 = graph2.hasEntity(this.entityIds[1]);
+          return entity1 && entity2 ? _t.append("issues.crossing_ways.message", {
+            feature: utilDisplayLabel(entity1, graph2),
+            feature2: utilDisplayLabel(entity2, graph2)
+          }) : "";
+        },
+        reference: showReference,
+        entityIds: entities.map(function(entity) {
+          return entity.id;
+        }),
+        data: {
+          edges,
+          featureTypes,
+          connectionTags
+        },
+        hash: uniqueID,
+        loc: crossing.crossPoint,
+        dynamicFixes: function(context2) {
+          var mode = context2.mode();
+          if (!mode || mode.id !== "select" || mode.selectedIDs().length !== 1) return [];
+          var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
+          var selectedFeatureType = this.data.featureTypes[selectedIndex];
+          var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
+          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({
+              icon: "iD-icon-layers",
+              title: _t.append("issues.fix.use_different_levels.title")
+            }));
+          } else if (isCrossingTunnels || isCrossingBridges || featureType1 === "building" || featureType2 === "building") {
+            fixes.push(makeChangeLayerFix("higher"));
+            fixes.push(makeChangeLayerFix("lower"));
+          } else if (context2.graph().geometry(this.entityIds[0]) === "line" && context2.graph().geometry(this.entityIds[1]) === "line") {
+            if (allowsBridge(selectedFeatureType) && selectedFeatureType !== "waterway") {
+              fixes.push(makeAddBridgeOrTunnelFix("add_a_bridge", "temaki-bridge", "bridge"));
+            }
+            var skipTunnelFix = otherFeatureType === "waterway" && selectedFeatureType !== "waterway";
+            if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
+              fixes.push(makeAddBridgeOrTunnelFix("add_a_tunnel", "temaki-tunnel", "tunnel"));
+            }
+          }
+          fixes.push(new validationIssueFix({
+            icon: "iD-operation-move",
+            title: _t.append("issues.fix.reposition_features.title")
+          }));
+          return fixes;
         }
       });
-      return result;
-    };
-    return cache;
-  }
-
-  // modules/core/uploader.js
-  function coreUploader(context) {
-    var dispatch10 = dispatch_default(
-      "saveStarted",
-      "saveEnded",
-      "willAttemptUpload",
-      "progressChanged",
-      "resultNoChanges",
-      "resultErrors",
-      "resultConflicts",
-      "resultSuccess"
-    );
-    var _isSaving = false;
-    var _conflicts = [];
-    var _errors = [];
-    var _origChanges;
-    var _discardTags = {};
-    _mainFileFetcher.get("discarded").then(function(d) {
-      _discardTags = d;
-    }).catch(function() {
-    });
-    var uploader = utilRebind({}, dispatch10, "on");
-    uploader.isSaving = function() {
-      return _isSaving;
-    };
-    uploader.save = function(changeset, tryAgain, checkConflicts) {
-      if (_isSaving && !tryAgain) {
-        return;
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.crossing_ways." + crossingTypeID + ".reference"));
       }
-      var osm = context.connection();
-      if (!osm)
-        return;
-      if (!osm.authenticated()) {
-        osm.authenticate(function(err) {
-          if (!err) {
-            uploader.save(changeset, tryAgain, checkConflicts);
+    }
+    function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
+      return new validationIssueFix({
+        icon: iconName,
+        title: _t.append("issues.fix." + fixTitleID + ".title"),
+        onClick: function(context2) {
+          var mode = context2.mode();
+          if (!mode || mode.id !== "select") return;
+          var selectedIDs = mode.selectedIDs();
+          if (selectedIDs.length !== 1) return;
+          var selectedWayID = selectedIDs[0];
+          if (!context2.hasEntity(selectedWayID)) return;
+          var resultWayIDs = [selectedWayID];
+          var edge, crossedEdge, crossedWayID;
+          if (this.issue.entityIds[0] === selectedWayID) {
+            edge = this.issue.data.edges[0];
+            crossedEdge = this.issue.data.edges[1];
+            crossedWayID = this.issue.entityIds[1];
+          } else {
+            edge = this.issue.data.edges[1];
+            crossedEdge = this.issue.data.edges[0];
+            crossedWayID = this.issue.entityIds[0];
           }
-        });
-        return;
-      }
-      if (!_isSaving) {
-        _isSaving = true;
-        dispatch10.call("saveStarted", this);
-      }
-      var history = context.history();
-      _conflicts = [];
-      _errors = [];
-      _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags));
-      if (!tryAgain) {
-        history.perform(actionNoop());
-      }
-      if (!checkConflicts) {
-        upload(changeset);
-      } else {
-        performFullConflictCheck(changeset);
-      }
-    };
-    function performFullConflictCheck(changeset) {
-      var osm = context.connection();
-      if (!osm)
-        return;
-      var history = context.history();
-      var localGraph = context.graph();
-      var remoteGraph = coreGraph(history.base(), true);
-      var summary = history.difference().summary();
-      var _toCheck = [];
-      for (var i2 = 0; i2 < summary.length; i2++) {
-        var item = summary[i2];
-        if (item.changeType === "modified") {
-          _toCheck.push(item.entity.id);
-        }
-      }
-      var _toLoad = withChildNodes(_toCheck, localGraph);
-      var _loaded = {};
-      var _toLoadCount = 0;
-      var _toLoadTotal = _toLoad.length;
-      if (_toCheck.length) {
-        dispatch10.call("progressChanged", this, _toLoadCount, _toLoadTotal);
-        _toLoad.forEach(function(id2) {
-          _loaded[id2] = false;
-        });
-        osm.loadMultiple(_toLoad, loaded);
-      } else {
-        upload(changeset);
-      }
-      return;
-      function withChildNodes(ids, graph) {
-        var s = new Set(ids);
-        ids.forEach(function(id2) {
-          var entity = graph.entity(id2);
-          if (entity.type !== "way")
-            return;
-          graph.childNodes(entity).forEach(function(child) {
-            if (child.version !== void 0) {
-              s.add(child.id);
+          var crossingLoc = this.issue.loc;
+          var projection2 = context2.projection;
+          var action = function actionAddStructure(graph) {
+            var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
+            var crossedWay = graph.hasEntity(crossedWayID);
+            var structLengthMeters = crossedWay && isFinite(crossedWay.tags.width) && Number(crossedWay.tags.width);
+            if (!structLengthMeters) {
+              structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
             }
-          });
-        });
-        return Array.from(s);
-      }
-      function loaded(err, result) {
-        if (_errors.length)
-          return;
-        if (err) {
-          _errors.push({
-            msg: err.message || err.responseText,
-            details: [_t("save.status_code", { code: err.status })]
-          });
-          didResultInErrors();
-        } else {
-          var loadMore = [];
-          result.data.forEach(function(entity) {
-            remoteGraph.replace(entity);
-            _loaded[entity.id] = true;
-            _toLoad = _toLoad.filter(function(val) {
-              return val !== entity.id;
-            });
-            if (!entity.visible)
-              return;
-            var i3, id2;
-            if (entity.type === "way") {
-              for (i3 = 0; i3 < entity.nodes.length; i3++) {
-                id2 = entity.nodes[i3];
-                if (_loaded[id2] === void 0) {
-                  _loaded[id2] = false;
-                  loadMore.push(id2);
-                }
+            if (structLengthMeters) {
+              if (getFeatureType(crossedWay, graph) === "railway") {
+                structLengthMeters *= 2;
               }
-            } else if (entity.type === "relation" && entity.isMultipolygon()) {
-              for (i3 = 0; i3 < entity.members.length; i3++) {
-                id2 = entity.members[i3].id;
-                if (_loaded[id2] === void 0) {
-                  _loaded[id2] = false;
-                  loadMore.push(id2);
+            } else {
+              structLengthMeters = 8;
+            }
+            var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection2) + Math.PI;
+            var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection2) + Math.PI;
+            var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
+            if (crossingAngle > Math.PI) crossingAngle -= Math.PI;
+            structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2;
+            structLengthMeters += 4;
+            structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
+            function geomToProj(geoPoint) {
+              return [
+                geoLonToMeters(geoPoint[0], geoPoint[1]),
+                geoLatToMeters(geoPoint[1])
+              ];
+            }
+            function projToGeom(projPoint) {
+              var lat = geoMetersToLat(projPoint[1]);
+              return [
+                geoMetersToLon(projPoint[0], lat),
+                lat
+              ];
+            }
+            var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
+            var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
+            var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
+            var projectedCrossingLoc = geomToProj(crossingLoc);
+            var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
+            function locSphericalDistanceFromCrossingLoc(angle2, distanceMeters) {
+              var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
+              return projToGeom([
+                projectedCrossingLoc[0] + Math.cos(angle2) * lengthSphericalMeters,
+                projectedCrossingLoc[1] + Math.sin(angle2) * lengthSphericalMeters
+              ]);
+            }
+            var endpointLocGetter1 = function(lengthMeters) {
+              return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
+            };
+            var endpointLocGetter2 = function(lengthMeters) {
+              return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
+            };
+            var minEdgeLengthMeters = 0.55;
+            function determineEndpoint(edge2, endNode, locGetter) {
+              var newNode;
+              var idealLengthMeters = structLengthMeters / 2;
+              var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
+              if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
+                var idealNodeLoc = locGetter(idealLengthMeters);
+                newNode = osmNode();
+                graph = actionAddMidpoint({ loc: idealNodeLoc, edge: edge2 }, newNode)(graph);
+              } else {
+                var edgeCount = 0;
+                endNode.parentIntersectionWays(graph).forEach(function(way) {
+                  way.nodes.forEach(function(nodeID) {
+                    if (nodeID === endNode.id) {
+                      if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
+                        edgeCount += 1;
+                      } else {
+                        edgeCount += 2;
+                      }
+                    }
+                  });
+                });
+                if (edgeCount >= 3) {
+                  var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
+                  if (insetLength > minEdgeLengthMeters) {
+                    var insetNodeLoc = locGetter(insetLength);
+                    newNode = osmNode();
+                    graph = actionAddMidpoint({ loc: insetNodeLoc, edge: edge2 }, newNode)(graph);
+                  }
                 }
               }
+              if (!newNode) newNode = endNode;
+              var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs);
+              graph = splitAction(graph);
+              if (splitAction.getCreatedWayIDs().length) {
+                resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
+              }
+              return newNode;
             }
-          });
-          _toLoadCount += result.data.length;
-          _toLoadTotal += loadMore.length;
-          dispatch10.call("progressChanged", this, _toLoadCount, _toLoadTotal);
-          if (loadMore.length) {
-            _toLoad.push.apply(_toLoad, loadMore);
-            osm.loadMultiple(loadMore, loaded);
-          }
-          if (!_toLoad.length) {
-            detectConflicts();
-            upload(changeset);
-          }
-        }
-      }
-      function detectConflicts() {
-        function choice(id2, text2, action) {
-          return {
-            id: id2,
-            text: text2,
-            action: function() {
-              history.replace(action);
+            var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
+            var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
+            var structureWay = resultWayIDs.map(function(id2) {
+              return graph.entity(id2);
+            }).find(function(way) {
+              return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
+            });
+            var tags = Object.assign({}, structureWay.tags);
+            if (bridgeOrTunnel === "bridge") {
+              tags.bridge = "yes";
+              tags.layer = "1";
+            } else {
+              var tunnelValue = "yes";
+              if (getFeatureType(structureWay, graph) === "waterway") {
+                tunnelValue = "culvert";
+              }
+              tags.tunnel = tunnelValue;
+              tags.layer = "-1";
             }
+            graph = actionChangeTags(structureWay.id, tags)(graph);
+            return graph;
           };
+          context2.perform(action, _t("issues.fix." + fixTitleID + ".annotation"));
+          context2.enter(modeSelect(context2, resultWayIDs));
         }
-        function formatUser(d) {
-          return '<a href="' + osm.userURL(d) + '" target="_blank">' + escape_default(d) + "</a>";
-        }
-        function entityName(entity) {
-          return utilDisplayName(entity) || utilDisplayType(entity.id) + " " + entity.id;
+      });
+    }
+    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";
+      }
+      const fix = new validationIssueFix({
+        icon: fixIcon,
+        title: _t.append("issues.fix." + fixTitleID + ".title"),
+        onClick: function(context2) {
+          var loc = this.issue.loc;
+          var edges = this.issue.data.edges;
+          context2.perform(
+            function actionConnectCrossingWays(graph) {
+              var node = osmNode({ loc, tags: connectionTags });
+              graph = graph.replace(node);
+              var nodesToMerge = [node.id];
+              var mergeThresholdInMeters = 0.75;
+              edges.forEach(function(edge) {
+                var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
+                var nearby = geoSphericalClosestNode(edgeNodes, loc);
+                if ((!nearby.node.hasInterestingTags() || nearby.node.isCrossing()) && nearby.distance < mergeThresholdInMeters) {
+                  nodesToMerge.push(nearby.node.id);
+                } else {
+                  graph = actionAddMidpoint({ loc, edge }, node)(graph);
+                }
+              });
+              if (nodesToMerge.length > 1) {
+                graph = actionMergeNodes(nodesToMerge, loc)(graph);
+              }
+              return graph;
+            },
+            _t("issues.fix.connect_crossing_features.annotation")
+          );
         }
-        function sameVersions(local, remote) {
-          if (local.version !== remote.version)
-            return false;
-          if (local.type === "way") {
-            var children2 = utilArrayUnion(local.nodes, remote.nodes);
-            for (var i3 = 0; i3 < children2.length; i3++) {
-              var a = localGraph.hasEntity(children2[i3]);
-              var b = remoteGraph.hasEntity(children2[i3]);
-              if (a && b && a.version !== b.version)
-                return false;
+      });
+      fix._connectionTags = connectionTags;
+      return fix;
+    }
+    function makeChangeLayerFix(higherOrLower) {
+      return new validationIssueFix({
+        icon: "iD-icon-" + (higherOrLower === "higher" ? "up" : "down"),
+        title: _t.append("issues.fix.tag_this_as_" + higherOrLower + ".title"),
+        onClick: function(context2) {
+          var mode = context2.mode();
+          if (!mode || mode.id !== "select") return;
+          var selectedIDs = mode.selectedIDs();
+          if (selectedIDs.length !== 1) return;
+          var selectedID = selectedIDs[0];
+          if (!this.issue.entityIds.some(function(entityId) {
+            return entityId === selectedID;
+          })) return;
+          var entity = context2.hasEntity(selectedID);
+          if (!entity) return;
+          var tags = Object.assign({}, entity.tags);
+          var layer = tags.layer && Number(tags.layer);
+          if (layer && !isNaN(layer)) {
+            if (higherOrLower === "higher") {
+              layer += 1;
+            } else {
+              layer -= 1;
+            }
+          } else {
+            if (higherOrLower === "higher") {
+              layer = 1;
+            } else {
+              layer = -1;
             }
           }
-          return true;
+          tags.layer = layer.toString();
+          context2.perform(
+            actionChangeTags(entity.id, tags),
+            _t("operations.change_tags.annotation")
+          );
         }
-        _toCheck.forEach(function(id2) {
-          var local = localGraph.entity(id2);
-          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();
-          if (!mergeConflicts.length)
-            return;
-          var forceLocal = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags).withOption("force_local");
-          var forceRemote = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags).withOption("force_remote");
-          var keepMine = _t("save.conflict." + (remote.visible ? "keep_local" : "restore"));
-          var keepTheirs = _t("save.conflict." + (remote.visible ? "keep_remote" : "delete"));
-          _conflicts.push({
-            id: id2,
-            name: entityName(local),
-            details: mergeConflicts,
-            chosen: 1,
-            choices: [
-              choice(id2, keepMine, forceLocal),
-              choice(id2, keepTheirs, forceRemote)
-            ]
-          });
-        });
-      }
+      });
     }
-    function upload(changeset) {
-      var osm = context.connection();
-      if (!osm) {
-        _errors.push({ msg: "No OSM Service" });
-      }
-      if (_conflicts.length) {
-        didResultInConflicts(changeset);
-      } else if (_errors.length) {
-        didResultInErrors();
-      } else {
-        var history = context.history();
-        var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
-        if (changes.modified.length || changes.created.length || changes.deleted.length) {
-          dispatch10.call("willAttemptUpload", this);
-          osm.putChangeset(changeset, changes, uploadCallback);
-        } else {
-          didResultInNoChanges();
+    validation.type = type2;
+    return validation;
+  }
+
+  // modules/behavior/draw_way.js
+  function behaviorDrawWay(context, wayID, mode, startGraph) {
+    const keybinding = utilKeybinding("drawWay");
+    var dispatch14 = dispatch_default("rejectedSelfIntersection");
+    var behavior = behaviorDraw(context);
+    var _nodeIndex;
+    var _origWay;
+    var _wayGeometry;
+    var _headNodeID;
+    var _annotation;
+    var _pointerHasMoved = false;
+    var _drawNode;
+    var _didResolveTempEdit = false;
+    function createDrawNode(loc) {
+      _drawNode = osmNode({ loc });
+      context.pauseChangeDispatch();
+      context.replace(function actionAddDrawNode(graph) {
+        var way = graph.entity(wayID);
+        return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
+      }, _annotation);
+      context.resumeChangeDispatch();
+      setActiveElements();
+    }
+    function removeDrawNode() {
+      context.pauseChangeDispatch();
+      context.replace(
+        function actionDeleteDrawNode(graph) {
+          var way = graph.entity(wayID);
+          return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
+        },
+        _annotation
+      );
+      _drawNode = void 0;
+      context.resumeChangeDispatch();
+    }
+    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 uploadCallback(err, changeset) {
-      if (err) {
-        if (err.status === 409) {
-          uploader.save(changeset, true, true);
-        } else {
-          _errors.push({
-            msg: err.message || err.responseText,
-            details: [_t("save.status_code", { code: err.status })]
-          });
-          didResultInErrors();
+    function keyup(d3_event) {
+      if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
+        if (context.surface().classed("nope-suppressed")) {
+          context.surface().classed("nope", true);
         }
-      } else {
-        didResultInSuccess(changeset);
+        context.surface().classed("nope-suppressed", false).classed("nope-disabled", false);
       }
     }
-    function didResultInNoChanges() {
-      dispatch10.call("resultNoChanges", this);
-      endSave();
-      context.flush();
-    }
-    function didResultInErrors() {
-      context.history().pop();
-      dispatch10.call("resultErrors", this, _errors);
-      endSave();
-    }
-    function didResultInConflicts(changeset) {
-      _conflicts.sort(function(a, b) {
-        return b.id.localeCompare(a.id);
-      });
-      dispatch10.call("resultConflicts", this, changeset, _conflicts, _origChanges);
-      endSave();
+    function allowsVertex(d2) {
+      return d2.geometry(context.graph()) === "vertex" || _mainPresetIndex.allowsVertex(d2, context.graph());
     }
-    function didResultInSuccess(changeset) {
-      context.history().clearSaved();
-      dispatch10.call("resultSuccess", this, changeset);
-      window.setTimeout(function() {
-        endSave();
-        context.flush();
-      }, 2500);
+    function move(d3_event, datum2) {
+      var loc = context.map().mouseCoordinates();
+      if (!_drawNode) createDrawNode(loc);
+      context.surface().classed("nope-disabled", d3_event.altKey);
+      var targetLoc = datum2 && datum2.properties && datum2.properties.entity && allowsVertex(datum2.properties.entity) && datum2.properties.entity.loc;
+      var targetNodes = datum2 && datum2.properties && datum2.properties.nodes;
+      if (targetLoc) {
+        loc = targetLoc;
+      } else if (targetNodes) {
+        var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
+        if (choice) {
+          loc = choice.loc;
+        }
+      }
+      context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
+      _drawNode = context.entity(_drawNode.id);
+      checkGeometry(
+        true
+        /* includeDrawNode */
+      );
     }
-    function endSave() {
-      _isSaving = false;
-      dispatch10.call("saveEnded", this);
+    function checkGeometry(includeDrawNode) {
+      var nopeDisabled = context.surface().classed("nope-disabled");
+      var isInvalid = isInvalidGeometry(includeDrawNode);
+      if (nopeDisabled) {
+        context.surface().classed("nope", false).classed("nope-suppressed", isInvalid);
+      } else {
+        context.surface().classed("nope", isInvalid).classed("nope-suppressed", false);
+      }
     }
-    uploader.cancelConflictResolution = function() {
-      context.history().pop();
-    };
-    uploader.processResolvedConflicts = function(changeset) {
-      var history = context.history();
-      for (var i2 = 0; i2 < _conflicts.length; i2++) {
-        if (_conflicts[i2].chosen === 1) {
-          var entity = context.hasEntity(_conflicts[i2].id);
-          if (entity && entity.type === "way") {
-            var children2 = utilArrayUniq(entity.nodes);
-            for (var j2 = 0; j2 < children2.length; j2++) {
-              history.replace(actionRevert(children2[j2]));
-            }
-          }
-          history.replace(actionRevert(_conflicts[i2].id));
+    function isInvalidGeometry(includeDrawNode) {
+      var testNode = _drawNode;
+      var parentWay = context.graph().entity(wayID);
+      var nodes = context.graph().childNodes(parentWay).slice();
+      if (includeDrawNode) {
+        if (parentWay.isClosed()) {
+          nodes.pop();
+        }
+      } else {
+        if (parentWay.isClosed()) {
+          if (nodes.length < 3) return false;
+          if (_drawNode) nodes.splice(-2, 1);
+          testNode = nodes[nodes.length - 2];
+        } else {
+          return false;
         }
       }
-      uploader.save(changeset, true, false);
-    };
-    uploader.reset = function() {
-    };
-    return uploader;
-  }
-
-  // modules/renderer/background_source.js
-  var import_lodash2 = __toESM(require_lodash());
-
-  // modules/util/IntervalTasksQueue.js
-  var IntervalTasksQueue = class {
-    constructor(intervalInMs) {
-      this.intervalInMs = intervalInMs;
-      this.pendingHandles = [];
-      this.time = 0;
+      return testNode && geoHasSelfIntersections(nodes, testNode.id);
     }
-    enqueue(task) {
-      let taskTimeout = this.time;
-      this.time += this.intervalInMs;
-      this.pendingHandles.push(setTimeout(() => {
-        this.time -= this.intervalInMs;
-        task();
-      }, taskTimeout));
+    function undone() {
+      _didResolveTempEdit = true;
+      context.pauseChangeDispatch();
+      var nextMode;
+      if (context.graph() === startGraph) {
+        nextMode = modeSelect(context, [wayID]);
+      } else {
+        context.pop(1);
+        nextMode = mode;
+      }
+      context.perform(actionNoop());
+      context.pop(1);
+      context.resumeChangeDispatch();
+      context.enter(nextMode);
     }
-    clear() {
-      this.pendingHandles.forEach((timeoutHandle) => {
-        clearTimeout(timeoutHandle);
-      });
-      this.pendingHandles = [];
-      this.time = 0;
+    function setActiveElements() {
+      if (!_drawNode) return;
+      context.surface().selectAll("." + _drawNode.id).classed("active", true);
     }
-  };
-
-  // modules/renderer/background_source.js
-  var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
-  window.matchMedia(`
-        (-webkit-min-device-pixel-ratio: 2), /* Safari */
-        (min-resolution: 2dppx),             /* standard */
-        (min-resolution: 192dpi)             /* fallback */
-    `).addListener(function() {
-    isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
-  });
-  function localeDateString(s) {
-    if (!s)
-      return null;
-    var options2 = { day: "numeric", month: "short", year: "numeric" };
-    var d = new Date(s);
-    if (isNaN(d.getTime()))
-      return null;
-    return d.toLocaleDateString(_mainLocalizer.localeCode(), options2);
-  }
-  function vintageRange(vintage) {
-    var s;
-    if (vintage.start || vintage.end) {
-      s = vintage.start || "?";
-      if (vintage.start !== vintage.end) {
-        s += " - " + (vintage.end || "?");
+    function resetToStartGraph() {
+      while (context.graph() !== startGraph) {
+        context.pop();
       }
     }
-    return s;
-  }
-  function rendererBackgroundSource(data) {
-    var source = Object.assign({}, data);
-    var _offset = [0, 0];
-    var _name = source.name;
-    var _description = source.description;
-    var _best = !!source.best;
-    var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
-    source.tileSize = data.tileSize || 256;
-    source.zoomExtent = data.zoomExtent || [0, 22];
-    source.overzoom = data.overzoom !== false;
-    source.offset = function(val) {
-      if (!arguments.length)
-        return _offset;
-      _offset = val;
-      return source;
-    };
-    source.nudge = function(val, zoomlevel) {
-      _offset[0] += val[0] / Math.pow(2, zoomlevel);
-      _offset[1] += val[1] / Math.pow(2, zoomlevel);
-      return source;
-    };
-    source.name = function() {
-      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
-      return _t("imagery." + id_safe + ".name", { default: (0, import_lodash2.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) });
-    };
-    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) });
-    };
-    source.best = function() {
-      return _best;
-    };
-    source.area = function() {
-      if (!data.polygon)
-        return Number.MAX_VALUE;
-      var area = area_default({ type: "MultiPolygon", coordinates: [data.polygon] });
-      return isNaN(area) ? 0 : area;
-    };
-    source.imageryUsed = function() {
-      return _name || source.id;
+    var drawWay = function(surface) {
+      _drawNode = void 0;
+      _didResolveTempEdit = false;
+      _origWay = context.entity(wayID);
+      if (typeof _nodeIndex === "number") {
+        _headNodeID = _origWay.nodes[_nodeIndex];
+      } else if (_origWay.isClosed()) {
+        _headNodeID = _origWay.nodes[_origWay.nodes.length - 2];
+      } else {
+        _headNodeID = _origWay.nodes[_origWay.nodes.length - 1];
+      }
+      _wayGeometry = _origWay.geometry(context.graph());
+      _annotation = _t(
+        (_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? "operations.start.annotation." : "operations.continue.annotation.") + _wayGeometry
+      );
+      _pointerHasMoved = false;
+      context.pauseChangeDispatch();
+      context.perform(actionNoop(), _annotation);
+      context.resumeChangeDispatch();
+      behavior.hover().initialNodeID(_headNodeID);
+      behavior.on("move", function() {
+        _pointerHasMoved = true;
+        move.apply(this, arguments);
+      }).on("down", function() {
+        move.apply(this, arguments);
+      }).on("downcancel", function() {
+        if (_drawNode) removeDrawNode();
+      }).on("click", drawWay.add).on("clickWay", drawWay.addWay).on("clickNode", drawWay.addNode).on("undo", context.undo).on("cancel", drawWay.cancel).on("finish", drawWay.finish);
+      select_default2(window).on("keydown.drawWay", keydown).on("keyup.drawWay", keyup);
+      context.map().dblclickZoomEnable(false).on("drawn.draw", setActiveElements);
+      setActiveElements();
+      surface.call(behavior);
+      context.history().on("undone.draw", undone);
     };
-    source.template = function(val) {
-      if (!arguments.length)
-        return _template;
-      if (source.id === "custom" || source.id === "Bing") {
-        _template = val;
+    drawWay.off = function(surface) {
+      if (!_didResolveTempEdit) {
+        context.pauseChangeDispatch();
+        resetToStartGraph();
+        context.resumeChangeDispatch();
       }
-      return source;
+      _drawNode = void 0;
+      _nodeIndex = void 0;
+      context.map().on("drawn.draw", null);
+      surface.call(behavior.off).selectAll(".active").classed("active", false);
+      surface.classed("nope", false).classed("nope-suppressed", false).classed("nope-disabled", false);
+      select_default2(window).on("keydown.drawWay", null).on("keyup.drawWay", null);
+      context.history().on("undone.draw", null);
     };
-    source.url = function(coord2) {
-      var result = _template.replace(/#[\s\S]*/u, "");
-      if (result === "")
-        return result;
-      if (!source.type || source.id === "custom") {
-        if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(result)) {
-          source.type = "wms";
-          source.projection = "EPSG:3857";
-        } else if (/\{(x|y)\}/.test(result)) {
-          source.type = "tms";
-        } else if (/\{u\}/.test(result)) {
-          source.type = "bing";
-        }
+    function attemptAdd(d2, loc, doAdd) {
+      if (_drawNode) {
+        context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
+        _drawNode = context.entity(_drawNode.id);
+      } else {
+        createDrawNode(loc);
       }
-      if (source.type === "wms") {
-        var tileToProjectedCoords = function(x, y, z) {
-          var zoomSize = Math.pow(2, z);
-          var lon = x / zoomSize * Math.PI * 2 - Math.PI;
-          var lat = Math.atan(Math.sinh(Math.PI * (1 - 2 * y / zoomSize)));
-          switch (source.projection) {
-            case "EPSG:4326":
-              return {
-                x: lon * 180 / Math.PI,
-                y: lat * 180 / Math.PI
-              };
-            default:
-              var mercCoords = mercatorRaw(lon, lat);
-              return {
-                x: 2003750834e-2 / Math.PI * mercCoords[0],
-                y: 2003750834e-2 / Math.PI * mercCoords[1]
-              };
-          }
-        };
-        var tileSize = source.tileSize;
-        var projection2 = source.projection;
-        var minXmaxY = tileToProjectedCoords(coord2[0], coord2[1], coord2[2]);
-        var maxXminY = tileToProjectedCoords(coord2[0] + 1, coord2[1] + 1, coord2[2]);
-        result = result.replace(/\{(\w+)\}/g, function(token, key) {
-          switch (key) {
-            case "width":
-            case "height":
-              return tileSize;
-            case "proj":
-              return projection2;
-            case "wkid":
-              return projection2.replace(/^EPSG:/, "");
-            case "bbox":
-              if (projection2 === "EPSG:4326" && /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
-                return maxXminY.y + "," + minXmaxY.x + "," + minXmaxY.y + "," + maxXminY.x;
-              } else {
-                return minXmaxY.x + "," + maxXminY.y + "," + maxXminY.x + "," + minXmaxY.y;
-              }
-            case "w":
-              return minXmaxY.x;
-            case "s":
-              return maxXminY.y;
-            case "n":
-              return maxXminY.x;
-            case "e":
-              return minXmaxY.y;
-            default:
-              return token;
-          }
-        });
-      } else if (source.type === "tms") {
-        result = result.replace("{x}", coord2[0]).replace("{y}", coord2[1]).replace(/\{[t-]y\}/, Math.pow(2, coord2[2]) - coord2[1] - 1).replace(/\{z(oom)?\}/, coord2[2]).replace(/\{@2x\}|\{r\}/, isRetina ? "@2x" : "");
-      } else if (source.type === "bing") {
-        result = result.replace("{u}", function() {
-          var u = "";
-          for (var zoom = coord2[2]; zoom > 0; zoom--) {
-            var b = 0;
-            var mask = 1 << zoom - 1;
-            if ((coord2[0] & mask) !== 0)
-              b++;
-            if ((coord2[1] & mask) !== 0)
-              b += 2;
-            u += b.toString();
-          }
-          return u;
-        });
+      checkGeometry(
+        true
+        /* includeDrawNode */
+      );
+      if (d2 && d2.properties && d2.properties.nope || context.surface().classed("nope")) {
+        if (!_pointerHasMoved) {
+          removeDrawNode();
+        }
+        dispatch14.call("rejectedSelfIntersection", this);
+        return;
       }
-      result = result.replace(/\{switch:([^}]+)\}/, function(s, r) {
-        var subdomains = r.split(",");
-        return subdomains[(coord2[0] + coord2[1]) % subdomains.length];
+      context.pauseChangeDispatch();
+      doAdd();
+      _didResolveTempEdit = true;
+      context.resumeChangeDispatch();
+      context.enter(mode);
+    }
+    drawWay.add = function(loc, d2) {
+      attemptAdd(d2, loc, function() {
       });
-      return result;
-    };
-    source.validZoom = function(z) {
-      return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
-    };
-    source.isLocatorOverlay = function() {
-      return source.id === "mapbox_locator_overlay";
-    };
-    source.isHidden = function() {
-      return source.id === "DigitalGlobe-Premium-vintage" || source.id === "DigitalGlobe-Standard-vintage";
-    };
-    source.copyrightNotices = function() {
-    };
-    source.getMetadata = function(center, tileCoord, callback) {
-      var vintage = {
-        start: localeDateString(source.startDate),
-        end: localeDateString(source.endDate)
-      };
-      vintage.range = vintageRange(vintage);
-      var metadata = { vintage };
-      callback(null, metadata);
     };
-    return source;
-  }
-  rendererBackgroundSource.Bing = function(data, dispatch10) {
-    data.template = "https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=1&pr=odbl&n=z";
-    var bing = rendererBackgroundSource(data);
-    var key = utilAesDecrypt("5c875730b09c6b422433e807e1ff060b6536c791dbfffcffc4c6b18a1bdba1f14593d151adb50e19e1be1ab19aef813bf135d0f103475e5c724dec94389e45d0");
-    const strictParam = "n";
-    var url = "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/AerialOSM?include=ImageryProviders&uriScheme=https&key=" + key;
-    var cache = {};
-    var inflight = {};
-    var providers = [];
-    var taskQueue = new IntervalTasksQueue(250);
-    var metadataLastZoom = -1;
-    json_default(url).then(function(json) {
-      let imageryResource = json.resourceSets[0].resources[0];
-      let template = imageryResource.imageUrl;
-      let subDomains = imageryResource.imageUrlSubdomains;
-      let subDomainNumbers = subDomains.map((subDomain) => {
-        return subDomain.substring(1);
-      }).join(",");
-      template = template.replace("{subdomain}", `t{switch:${subDomainNumbers}}`).replace("{quadkey}", "{u}");
-      if (!new URLSearchParams(template).has(strictParam)) {
-        template += `&${strictParam}=z`;
-      }
-      bing.template(template);
-      providers = imageryResource.imageryProviders.map(function(provider) {
-        return {
-          attribution: provider.attribution,
-          areas: provider.coverageAreas.map(function(area) {
-            return {
-              zoom: [area.zoomMin, area.zoomMax],
-              extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
-            };
-          })
-        };
+    drawWay.addWay = function(loc, edge, d2) {
+      attemptAdd(d2, loc, function() {
+        context.replace(
+          actionAddMidpoint({ loc, edge }, _drawNode),
+          _annotation
+        );
       });
-      dispatch10.call("change");
-    }).catch(function() {
-    });
-    bing.copyrightNotices = function(zoom, extent) {
-      zoom = Math.min(zoom, 21);
-      return providers.filter(function(provider) {
-        return provider.areas.some(function(area) {
-          return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
-        });
-      }).map(function(provider) {
-        return provider.attribution;
-      }).join(", ");
     };
-    bing.getMetadata = function(center, tileCoord, callback) {
-      var tileID = tileCoord.slice(0, 3).join("/");
-      var zoom = Math.min(tileCoord[2], 21);
-      var centerPoint = center[1] + "," + center[0];
-      var url2 = "https://dev.virtualearth.net/REST/v1/Imagery/BasicMetadata/AerialOSM/" + centerPoint + "?zl=" + zoom + "&key=" + key;
-      if (inflight[tileID])
+    drawWay.addNode = function(node, d2) {
+      if (node.id === _headNodeID || // or the first node when drawing an area
+      _origWay.isClosed() && node.id === _origWay.first()) {
+        drawWay.finish();
         return;
-      if (!cache[tileID]) {
-        cache[tileID] = {};
-      }
-      if (cache[tileID] && cache[tileID].metadata) {
-        return callback(null, cache[tileID].metadata);
-      }
-      inflight[tileID] = true;
-      if (metadataLastZoom !== tileCoord[2]) {
-        metadataLastZoom = tileCoord[2];
-        taskQueue.clear();
       }
-      taskQueue.enqueue(() => {
-        json_default(url2).then(function(result) {
-          delete inflight[tileID];
-          if (!result) {
-            throw new Error("Unknown Error");
-          }
-          var vintage = {
-            start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
-            end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
-          };
-          vintage.range = vintageRange(vintage);
-          var metadata = { vintage };
-          cache[tileID].metadata = metadata;
-          if (callback)
-            callback(null, metadata);
-        }).catch(function(err) {
-          delete inflight[tileID];
-          if (callback)
-            callback(err.message);
-        });
+      attemptAdd(d2, node.loc, function() {
+        context.replace(
+          function actionReplaceDrawNode(graph) {
+            graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
+            return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
+          },
+          _annotation
+        );
       });
     };
-    bing.terms_url = "https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details";
-    return bing;
-  };
-  rendererBackgroundSource.Esri = function(data) {
-    if (data.template.match(/blankTile/) === null) {
-      data.template = data.template + "?blankTile=false";
+    function getFeatureType(ways) {
+      if (ways.every((way) => way.isClosed())) return "area";
+      if (ways.every((way) => !way.isClosed())) return "line";
+      return "generic";
     }
-    var esri = rendererBackgroundSource(data);
-    var cache = {};
-    var inflight = {};
-    var _prevCenter;
-    esri.fetchTilemap = function(center) {
-      if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5e3)
-        return;
-      _prevCenter = center;
-      var z = 20;
-      var dummyUrl = esri.url([1, 2, 3]);
-      var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
-      var y = Math.floor((1 - Math.log(Math.tan(center[1] * Math.PI / 180) + 1 / Math.cos(center[1] * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, z));
-      var tilemapUrl = dummyUrl.replace(/tile\/[0-9]+\/[0-9]+\/[0-9]+\?blankTile=false/, "tilemap") + "/" + z + "/" + y + "/" + x + "/8/8";
-      json_default(tilemapUrl).then(function(tilemap) {
-        if (!tilemap) {
-          throw new Error("Unknown Error");
+    function followMode() {
+      if (_didResolveTempEdit) return;
+      try {
+        const isDrawingArea = _origWay.nodes[0] === _origWay.nodes.slice(-1)[0];
+        const [secondLastNodeId, lastNodeId] = _origWay.nodes.slice(isDrawingArea ? -3 : -2);
+        const historyGraph = context.history().graph();
+        if (!lastNodeId || !secondLastNodeId || !historyGraph.hasEntity(lastNodeId) || !historyGraph.hasEntity(secondLastNodeId)) {
+          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("operations.follow.error.needs_more_initial_nodes"))();
+          return;
         }
-        var hasTiles = true;
-        for (var i2 = 0; i2 < tilemap.data.length; i2++) {
-          if (!tilemap.data[i2]) {
-            hasTiles = false;
-            break;
-          }
+        const lastNodesParents = historyGraph.parentWays(historyGraph.entity(lastNodeId)).filter((w2) => w2.id !== wayID);
+        const secondLastNodesParents = historyGraph.parentWays(historyGraph.entity(secondLastNodeId)).filter((w2) => w2.id !== wayID);
+        const featureType = getFeatureType(lastNodesParents);
+        if (lastNodesParents.length !== 1 || secondLastNodesParents.length === 0) {
+          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("operations.follow.error.intersection_of_multiple_ways.".concat(featureType)))();
+          return;
         }
-        esri.zoomExtent[1] = hasTiles ? 22 : 19;
-      }).catch(function() {
-      });
-    };
-    esri.getMetadata = function(center, tileCoord, callback) {
-      if (esri.id !== "EsriWorldImagery") {
-        return callback(null, {});
+        if (!secondLastNodesParents.some((n3) => n3.id === lastNodesParents[0].id)) {
+          context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("operations.follow.error.intersection_of_different_ways.".concat(featureType)))();
+          return;
+        }
+        const way = lastNodesParents[0];
+        const indexOfLast = way.nodes.indexOf(lastNodeId);
+        const indexOfSecondLast = way.nodes.indexOf(secondLastNodeId);
+        const isDescendingPastZero = indexOfLast === way.nodes.length - 2 && indexOfSecondLast === 0;
+        let nextNodeIndex = indexOfLast + (indexOfLast > indexOfSecondLast && !isDescendingPastZero ? 1 : -1);
+        if (nextNodeIndex === -1) nextNodeIndex = indexOfSecondLast === 1 ? way.nodes.length - 2 : 1;
+        const nextNode = historyGraph.entity(way.nodes[nextNodeIndex]);
+        drawWay.addNode(nextNode, {
+          geometry: { type: "Point", coordinates: nextNode.loc },
+          id: nextNode.id,
+          properties: { target: true, entity: nextNode }
+        });
+      } catch {
+        context.ui().flash.duration(4e3).iconName("#iD-icon-no").label(_t.append("operations.follow.error.unknown"))();
       }
-      var tileID = tileCoord.slice(0, 3).join("/");
-      var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
-      var centerPoint = center[0] + "," + center[1];
-      var unknown = _t("info_panels.background.unknown");
-      var vintage = {};
-      var metadata = {};
-      if (inflight[tileID])
+    }
+    keybinding.on(_t("operations.follow.key"), followMode);
+    select_default2(document).call(keybinding);
+    drawWay.finish = function() {
+      checkGeometry(
+        false
+        /* includeDrawNode */
+      );
+      if (context.surface().classed("nope")) {
+        dispatch14.call("rejectedSelfIntersection", this);
         return;
-      var url = "https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/4/query";
-      url += "?returnGeometry=false&geometry=" + centerPoint + "&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json";
-      if (!cache[tileID]) {
-        cache[tileID] = {};
       }
-      if (cache[tileID] && cache[tileID].metadata) {
-        return callback(null, cache[tileID].metadata);
-      }
-      inflight[tileID] = true;
-      json_default(url).then(function(result) {
-        delete inflight[tileID];
-        result = result.features.map((f2) => f2.attributes).filter((a) => a.MinMapLevel <= zoom && a.MaxMapLevel >= zoom)[0];
-        if (!result) {
-          throw new Error("Unknown Error");
-        } else if (result.features && result.features.length < 1) {
-          throw new Error("No Results");
-        } else if (result.error && result.error.message) {
-          throw new Error(result.error.message);
-        }
-        var captureDate = localeDateString(result.SRC_DATE2);
-        vintage = {
-          start: captureDate,
-          end: captureDate,
-          range: captureDate
-        };
-        metadata = {
-          vintage,
-          source: clean2(result.NICE_NAME),
-          description: clean2(result.NICE_DESC),
-          resolution: clean2(+parseFloat(result.SRC_RES).toFixed(4)),
-          accuracy: clean2(+parseFloat(result.SRC_ACC).toFixed(4))
-        };
-        if (isFinite(metadata.resolution)) {
-          metadata.resolution += " m";
-        }
-        if (isFinite(metadata.accuracy)) {
-          metadata.accuracy += " m";
-        }
-        cache[tileID].metadata = metadata;
-        if (callback)
-          callback(null, metadata);
-      }).catch(function(err) {
-        delete inflight[tileID];
-        if (callback)
-          callback(err.message);
-      });
-      function clean2(val) {
-        return String(val).trim() || unknown;
+      context.pauseChangeDispatch();
+      context.pop(1);
+      _didResolveTempEdit = true;
+      context.resumeChangeDispatch();
+      var way = context.hasEntity(wayID);
+      if (!way || way.isDegenerate()) {
+        drawWay.cancel();
+        return;
       }
+      window.setTimeout(function() {
+        context.map().dblclickZoomEnable(true);
+      }, 1e3);
+      var isNewFeature = !mode.isContinuing;
+      context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
     };
-    return esri;
-  };
-  rendererBackgroundSource.None = function() {
-    var source = rendererBackgroundSource({ id: "none", template: "" });
-    source.name = function() {
-      return _t("background.none");
+    drawWay.cancel = function() {
+      context.pauseChangeDispatch();
+      resetToStartGraph();
+      context.resumeChangeDispatch();
+      window.setTimeout(function() {
+        context.map().dblclickZoomEnable(true);
+      }, 1e3);
+      context.surface().classed("nope", false).classed("nope-disabled", false).classed("nope-suppressed", false);
+      context.enter(modeBrowse(context));
     };
-    source.label = function() {
-      return _t.append("background.none");
+    drawWay.nodeIndex = function(val) {
+      if (!arguments.length) return _nodeIndex;
+      _nodeIndex = val;
+      return drawWay;
     };
-    source.imageryUsed = function() {
-      return null;
+    drawWay.activeID = function() {
+      if (!arguments.length) return _drawNode && _drawNode.id;
+      return drawWay;
     };
-    source.area = function() {
-      return -1;
+    return utilRebind(drawWay, dispatch14, "on");
+  }
+
+  // modules/modes/draw_line.js
+  function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
+    var mode = {
+      button,
+      id: "draw-line"
     };
-    return source;
-  };
-  rendererBackgroundSource.Custom = function(template) {
-    var source = rendererBackgroundSource({ id: "custom", template });
-    source.name = function() {
-      return _t("background.custom");
+    var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on("rejectedSelfIntersection.modeDrawLine", function() {
+      context.ui().flash.iconName("#iD-icon-no").label(_t.append("self_intersection.error.lines"))();
+    });
+    mode.wayID = wayID;
+    mode.isContinuing = continuing;
+    mode.enter = function() {
+      behavior.nodeIndex(affix === "prefix" ? 0 : void 0);
+      context.install(behavior);
     };
-    source.label = function() {
-      return _t.append("background.custom");
+    mode.exit = function() {
+      context.uninstall(behavior);
     };
-    source.imageryUsed = function() {
-      var cleaned = source.template();
-      if (cleaned.indexOf("?") !== -1) {
-        var parts = cleaned.split("?", 2);
-        var qs = utilStringQs(parts[1]);
-        ["access_token", "connectId", "token"].forEach(function(param) {
-          if (qs[param]) {
-            qs[param] = "{apikey}";
-          }
-        });
-        cleaned = parts[0] + "?" + utilQsString(qs, true);
-      }
-      cleaned = cleaned.replace(/token\/(\w+)/, "token/{apikey}").replace(/key=(\w+)/, "key={apikey}");
-      return "Custom (" + cleaned + " )";
+    mode.selectedIDs = function() {
+      return [wayID];
     };
-    source.area = function() {
-      return -2;
+    mode.activeID = function() {
+      return behavior && behavior.activeID() || [];
     };
-    return source;
-  };
-
-  // modules/renderer/background.js
-  var import_which_polygon4 = __toESM(require_which_polygon());
+    return mode;
+  }
 
-  // modules/renderer/tile_layer.js
-  function rendererTileLayer(context) {
-    var transformProp = utilPrefixCSSProperty("Transform");
-    var tiler8 = utilTiler();
-    var _tileSize = 256;
-    var _projection;
-    var _cache4 = {};
-    var _tileOrigin;
-    var _zoom;
-    var _source;
-    function tileSizeAtZoom(d, z) {
-      var EPSILON = 2e-3;
-      return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
-    }
-    function atZoom(t, distance) {
-      var power = Math.pow(2, distance);
-      return [
-        Math.floor(t[0] * power),
-        Math.floor(t[1] * power),
-        t[2] + distance
-      ];
-    }
-    function lookUp(d) {
-      for (var up = -1; up > -d[2]; up--) {
-        var tile = atZoom(d, up);
-        if (_cache4[_source.url(tile)] !== false) {
-          return tile;
-        }
-      }
-    }
-    function uniqueBy(a, n2) {
-      var o = [];
-      var seen = {};
-      for (var i2 = 0; i2 < a.length; i2++) {
-        if (seen[a[i2][n2]] === void 0) {
-          o.push(a[i2]);
-          seen[a[i2][n2]] = true;
-        }
-      }
-      return o;
-    }
-    function addSource(d) {
-      d.push(_source.url(d));
-      return d;
-    }
-    function background(selection2) {
-      _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
-      var pixelOffset;
-      if (_source) {
-        pixelOffset = [
-          _source.offset()[0] * Math.pow(2, _zoom),
-          _source.offset()[1] * Math.pow(2, _zoom)
-        ];
-      } else {
-        pixelOffset = [0, 0];
-      }
-      var translate = [
-        _projection.translate()[0] + pixelOffset[0],
-        _projection.translate()[1] + pixelOffset[1]
-      ];
-      tiler8.scale(_projection.scale() * 2 * Math.PI).translate(translate);
-      _tileOrigin = [
-        _projection.scale() * Math.PI - translate[0],
-        _projection.scale() * Math.PI - translate[1]
-      ];
-      render(selection2);
+  // modules/validations/disconnected_way.js
+  function validationDisconnectedWay() {
+    var type2 = "disconnected_way";
+    function isTaggedAsHighway(entity) {
+      return osmRoutableHighwayTagValues[entity.tags.highway];
     }
-    function render(selection2) {
-      if (!_source)
-        return;
-      var requests = [];
-      var showDebug = context.getDebug("tile") && !_source.overlay;
-      if (_source.validZoom(_zoom)) {
-        tiler8.skipNullIsland(!!_source.overlay);
-        tiler8().forEach(function(d) {
-          addSource(d);
-          if (d[3] === "")
-            return;
-          if (typeof d[3] !== "string")
-            return;
-          requests.push(d);
-          if (_cache4[d[3]] === false && lookUp(d)) {
-            requests.push(addSource(lookUp(d)));
+    var validation = function checkDisconnectedWay(entity, graph) {
+      var routingIslandWays = routingIslandForEntity(entity);
+      if (!routingIslandWays) return [];
+      return [new validationIssue({
+        type: type2,
+        subtype: "highway",
+        severity: "warning",
+        message: function(context) {
+          var entity2 = this.entityIds.length && context.hasEntity(this.entityIds[0]);
+          var label = entity2 && utilDisplayLabel(entity2, context.graph());
+          return _t.append("issues.disconnected_way.routable.message", { count: this.entityIds.length, highway: label });
+        },
+        reference: showReference,
+        entityIds: Array.from(routingIslandWays).map(function(way) {
+          return way.id;
+        }),
+        dynamicFixes: makeFixes
+      })];
+      function makeFixes(context) {
+        var fixes = [];
+        var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
+        if (singleEntity) {
+          if (singleEntity.type === "way" && !singleEntity.isClosed()) {
+            var textDirection = _mainLocalizer.textDirection();
+            var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), "start");
+            if (startFix) fixes.push(startFix);
+            var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), "end");
+            if (endFix) fixes.push(endFix);
           }
-        });
-        requests = uniqueBy(requests, 3).filter(function(r) {
-          return _cache4[r[3]] !== false;
-        });
-      }
-      function load(d3_event, d) {
-        _cache4[d[3]] = true;
-        select_default2(this).on("error", null).on("load", null).classed("tile-loaded", true);
-        render(selection2);
+          if (!fixes.length) {
+            fixes.push(new validationIssueFix({
+              title: _t.append("issues.fix.connect_feature.title")
+            }));
+          }
+          fixes.push(new validationIssueFix({
+            icon: "iD-operation-delete",
+            title: _t.append("issues.fix.delete_feature.title"),
+            entityIds: [singleEntity.id],
+            onClick: function(context2) {
+              var id2 = this.issue.entityIds[0];
+              var operation2 = operationDelete(context2, [id2]);
+              if (!operation2.disabled()) {
+                operation2();
+              }
+            }
+          }));
+        } else {
+          fixes.push(new validationIssueFix({
+            title: _t.append("issues.fix.connect_features.title")
+          }));
+        }
+        return fixes;
       }
-      function error(d3_event, d) {
-        _cache4[d[3]] = false;
-        select_default2(this).on("error", null).on("load", null).remove();
-        render(selection2);
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.disconnected_way.routable.reference"));
       }
-      function imageTransform(d) {
-        var ts = _tileSize * Math.pow(2, _zoom - d[2]);
-        var scale = tileSizeAtZoom(d, _zoom);
-        return "translate(" + (d[0] * ts - _tileOrigin[0]) + "px," + (d[1] * ts - _tileOrigin[1]) + "px) scale(" + scale + "," + scale + ")";
+      function routingIslandForEntity(entity2) {
+        var routingIsland = /* @__PURE__ */ new Set();
+        var waysToCheck = [];
+        function queueParentWays(node) {
+          graph.parentWays(node).forEach(function(parentWay) {
+            if (!routingIsland.has(parentWay) && // only check each feature once
+            isRoutableWay(parentWay, false)) {
+              routingIsland.add(parentWay);
+              waysToCheck.push(parentWay);
+            }
+          });
+        }
+        if (entity2.type === "way" && isRoutableWay(entity2, true)) {
+          routingIsland.add(entity2);
+          waysToCheck.push(entity2);
+        } else if (entity2.type === "node" && isRoutableNode(entity2)) {
+          routingIsland.add(entity2);
+          queueParentWays(entity2);
+        } else {
+          return null;
+        }
+        while (waysToCheck.length) {
+          var wayToCheck = waysToCheck.pop();
+          var childNodes = graph.childNodes(wayToCheck);
+          for (var i3 in childNodes) {
+            var vertex = childNodes[i3];
+            if (isConnectedVertex(vertex)) {
+              return null;
+            }
+            if (isRoutableNode(vertex)) {
+              routingIsland.add(vertex);
+            }
+            queueParentWays(vertex);
+          }
+        }
+        return routingIsland;
       }
-      function tileCenter(d) {
-        var ts = _tileSize * Math.pow(2, _zoom - d[2]);
-        return [
-          d[0] * ts - _tileOrigin[0] + ts / 2,
-          d[1] * ts - _tileOrigin[1] + ts / 2
-        ];
+      function isConnectedVertex(vertex) {
+        var osm = services.osm;
+        if (osm && !osm.isDataLoaded(vertex.loc)) return true;
+        if (vertex.tags.entrance && vertex.tags.entrance !== "no") return true;
+        if (vertex.tags.amenity === "parking_entrance") return true;
+        return false;
       }
-      function debugTransform(d) {
-        var coord2 = tileCenter(d);
-        return "translate(" + coord2[0] + "px," + coord2[1] + "px)";
+      function isRoutableNode(node) {
+        if (node.tags.highway === "elevator") return true;
+        return false;
       }
-      var dims = tiler8.size();
-      var mapCenter = [dims[0] / 2, dims[1] / 2];
-      var minDist = Math.max(dims[0], dims[1]);
-      var nearCenter;
-      requests.forEach(function(d) {
-        var c = tileCenter(d);
-        var dist = geoVecLength(c, mapCenter);
-        if (dist < minDist) {
-          minDist = dist;
-          nearCenter = d;
-        }
-      });
-      var image = selection2.selectAll("img").data(requests, function(d) {
-        return d[3];
-      });
-      image.exit().style(transformProp, imageTransform).classed("tile-removing", true).classed("tile-center", false).each(function() {
-        var tile = select_default2(this);
-        window.setTimeout(function() {
-          if (tile.classed("tile-removing")) {
-            tile.remove();
-          }
-        }, 300);
-      });
-      image.enter().append("img").attr("class", "tile").attr("alt", "").attr("draggable", "false").style("width", _tileSize + "px").style("height", _tileSize + "px").attr("src", function(d) {
-        return d[3];
-      }).on("error", error).on("load", load).merge(image).style(transformProp, imageTransform).classed("tile-debug", showDebug).classed("tile-removing", false).classed("tile-center", function(d) {
-        return d === nearCenter;
-      });
-      var debug2 = selection2.selectAll(".tile-label-debug").data(showDebug ? requests : [], function(d) {
-        return d[3];
-      });
-      debug2.exit().remove();
-      if (showDebug) {
-        var debugEnter = debug2.enter().append("div").attr("class", "tile-label-debug");
-        debugEnter.append("div").attr("class", "tile-label-debug-coord");
-        debugEnter.append("div").attr("class", "tile-label-debug-vintage");
-        debug2 = debug2.merge(debugEnter);
-        debug2.style(transformProp, debugTransform);
-        debug2.selectAll(".tile-label-debug-coord").text(function(d) {
-          return d[2] + " / " + d[0] + " / " + d[1];
+      function isRoutableWay(way, ignoreInnerWays) {
+        if (isTaggedAsHighway(way) || way.tags.route === "ferry") return true;
+        return graph.parentRelations(way).some(function(parentRelation) {
+          if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry") return true;
+          if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== "inner")) return true;
+          return false;
         });
-        debug2.selectAll(".tile-label-debug-vintage").each(function(d) {
-          var span = select_default2(this);
-          var center = context.projection.invert(tileCenter(d));
-          _source.getMetadata(center, d, function(err, result) {
-            if (result && result.vintage && result.vintage.range) {
-              span.text(result.vintage.range);
-            } else {
-              span.call(_t.append("info_panels.background.vintage"));
-              span.append("span").text(": ");
-              span.call(_t.append("info_panels.background.unknown"));
+      }
+      function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
+        var vertex = graph.hasEntity(vertexID);
+        if (!vertex || vertex.tags.noexit === "yes") return null;
+        var useLeftContinue = whichEnd === "start" && textDirection === "ltr" || whichEnd === "end" && textDirection === "rtl";
+        return new validationIssueFix({
+          icon: "iD-operation-continue" + (useLeftContinue ? "-left" : ""),
+          title: _t.append("issues.fix.continue_from_" + whichEnd + ".title"),
+          entityIds: [vertexID],
+          onClick: function(context) {
+            var wayId = this.issue.entityIds[0];
+            var way = context.hasEntity(wayId);
+            var vertexId = this.entityIds[0];
+            var vertex2 = context.hasEntity(vertexId);
+            if (!way || !vertex2) return;
+            var map2 = context.map();
+            if (!context.editable() || !map2.trimmedExtent().contains(vertex2.loc)) {
+              map2.zoomToEase(vertex2);
             }
-          });
+            context.enter(
+              modeDrawLine(context, wayId, context.graph(), "line", way.affix(vertexId), true)
+            );
+          }
         });
       }
-    }
-    background.projection = function(val) {
-      if (!arguments.length)
-        return _projection;
-      _projection = val;
-      return background;
-    };
-    background.dimensions = function(val) {
-      if (!arguments.length)
-        return tiler8.size();
-      tiler8.size(val);
-      return background;
-    };
-    background.source = function(val) {
-      if (!arguments.length)
-        return _source;
-      _source = val;
-      _tileSize = _source.tileSize;
-      _cache4 = {};
-      tiler8.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
-      return background;
     };
-    return background;
+    validation.type = type2;
+    return validation;
   }
 
-  // modules/renderer/background.js
-  var _imageryIndex = null;
-  function rendererBackground(context) {
-    const dispatch10 = dispatch_default("change");
-    const baseLayer = rendererTileLayer(context).projection(context.projection);
-    let _checkedBlocklists = [];
-    let _isValid = true;
-    let _overlayLayers = [];
-    let _brightness = 1;
-    let _contrast = 1;
-    let _saturation = 1;
-    let _sharpness = 1;
-    function ensureImageryIndex() {
-      return _mainFileFetcher.get("imagery").then((sources) => {
-        if (_imageryIndex)
-          return _imageryIndex;
-        _imageryIndex = {
-          imagery: sources,
-          features: {}
-        };
-        const features2 = sources.map((source) => {
-          if (!source.polygon)
-            return null;
-          const rings = source.polygon.map((ring) => [ring]);
-          const feature3 = {
-            type: "Feature",
-            properties: { id: source.id },
-            geometry: { type: "MultiPolygon", coordinates: rings }
-          };
-          _imageryIndex.features[source.id] = feature3;
-          return feature3;
-        }).filter(Boolean);
-        _imageryIndex.query = (0, import_which_polygon4.default)({ type: "FeatureCollection", features: features2 });
-        _imageryIndex.backgrounds = sources.map((source) => {
-          if (source.type === "bing") {
-            return rendererBackgroundSource.Bing(source, dispatch10);
-          } else if (/^EsriWorldImagery/.test(source.id)) {
-            return rendererBackgroundSource.Esri(source);
-          } else {
-            return rendererBackgroundSource(source);
-          }
-        });
-        _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None());
-        let template = corePreferences("background-custom-template") || "";
-        const custom = rendererBackgroundSource.Custom(template);
-        _imageryIndex.backgrounds.unshift(custom);
-        return _imageryIndex;
-      });
-    }
-    function background(selection2) {
-      const currSource = baseLayer.source();
-      if (context.map().zoom() > 18) {
-        if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
-          const center = context.map().center();
-          currSource.fetchTilemap(center);
-        }
-      }
-      const sources = background.sources(context.map().extent());
-      const wasValid = _isValid;
-      _isValid = !!sources.filter((d) => d === currSource).length;
-      if (wasValid !== _isValid) {
-        background.updateImagery();
-      }
-      let baseFilter = "";
-      if (_brightness !== 1) {
-        baseFilter += ` brightness(${_brightness})`;
-      }
-      if (_contrast !== 1) {
-        baseFilter += ` contrast(${_contrast})`;
-      }
-      if (_saturation !== 1) {
-        baseFilter += ` saturate(${_saturation})`;
-      }
-      if (_sharpness < 1) {
-        const blur = number_default(0.5, 5)(1 - _sharpness);
-        baseFilter += ` blur(${blur}px)`;
-      }
-      let base = selection2.selectAll(".layer-background").data([0]);
-      base = base.enter().insert("div", ".layer-data").attr("class", "layer layer-background").merge(base);
-      base.style("filter", baseFilter || null);
-      let imagery = base.selectAll(".layer-imagery").data([0]);
-      imagery.enter().append("div").attr("class", "layer layer-imagery").merge(imagery).call(baseLayer);
-      let maskFilter = "";
-      let mixBlendMode = "";
-      if (_sharpness > 1) {
-        mixBlendMode = "overlay";
-        maskFilter = "saturate(0) blur(3px) invert(1)";
-        let contrast = _sharpness - 1;
-        maskFilter += ` contrast(${contrast})`;
-        let brightness = number_default(1, 0.85)(_sharpness - 1);
-        maskFilter += ` brightness(${brightness})`;
-      }
-      let mask = base.selectAll(".layer-unsharp-mask").data(_sharpness > 1 ? [0] : []);
-      mask.exit().remove();
-      mask.enter().append("div").attr("class", "layer layer-mask layer-unsharp-mask").merge(mask).call(baseLayer).style("filter", maskFilter || null).style("mix-blend-mode", mixBlendMode || null);
-      let overlays = selection2.selectAll(".layer-overlay").data(_overlayLayers, (d) => d.source().name());
-      overlays.exit().remove();
-      overlays.enter().insert("div", ".layer-data").attr("class", "layer layer-overlay").merge(overlays).each((layer, i2, nodes) => select_default2(nodes[i2]).call(layer));
-    }
-    background.updateImagery = function() {
-      let currSource = baseLayer.source();
-      if (context.inIntro() || !currSource)
-        return;
-      let o = _overlayLayers.filter((d) => !d.source().isLocatorOverlay() && !d.source().isHidden()).map((d) => d.source().id).join(",");
-      const meters = geoOffsetToMeters(currSource.offset());
-      const EPSILON = 0.01;
-      const x = +meters[0].toFixed(2);
-      const y = +meters[1].toFixed(2);
-      let hash = utilStringQs(window.location.hash);
-      let id2 = currSource.id;
-      if (id2 === "custom") {
-        id2 = `custom:${currSource.template()}`;
-      }
-      if (id2) {
-        hash.background = id2;
-      } else {
-        delete hash.background;
-      }
-      if (o) {
-        hash.overlays = o;
-      } else {
-        delete hash.overlays;
-      }
-      if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
-        hash.offset = `${x},${y}`;
-      } else {
-        delete hash.offset;
-      }
-      if (!window.mocha) {
-        window.location.replace("#" + utilQsString(hash, true));
-      }
-      let imageryUsed = [];
-      let photoOverlaysUsed = [];
-      const currUsed = currSource.imageryUsed();
-      if (currUsed && _isValid) {
-        imageryUsed.push(currUsed);
-      }
-      _overlayLayers.filter((d) => !d.source().isLocatorOverlay() && !d.source().isHidden()).forEach((d) => imageryUsed.push(d.source().imageryUsed()));
-      const dataLayer = context.layers().layer("data");
-      if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
-        imageryUsed.push(dataLayer.getSrc());
+  // modules/validations/invalid_format.js
+  function validationFormatting() {
+    var type2 = "invalid_format";
+    var validation = function(entity) {
+      var issues = [];
+      function isValidEmail(email) {
+        var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i;
+        return !email || valid_email.test(email);
       }
-      const photoOverlayLayers = {
-        streetside: "Bing Streetside",
-        mapillary: "Mapillary Images",
-        "mapillary-map-features": "Mapillary Map Features",
-        "mapillary-signs": "Mapillary Signs",
-        kartaview: "KartaView Images"
-      };
-      for (let layerID in photoOverlayLayers) {
-        const layer = context.layers().layer(layerID);
-        if (layer && layer.enabled()) {
-          photoOverlaysUsed.push(layerID);
-          imageryUsed.push(photoOverlayLayers[layerID]);
-        }
+      function showReferenceEmail(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.invalid_format.email.reference"));
       }
-      context.history().imageryUsed(imageryUsed);
-      context.history().photoOverlaysUsed(photoOverlaysUsed);
-    };
-    background.sources = (extent, zoom, includeCurrent) => {
-      if (!_imageryIndex)
-        return [];
-      let visible = {};
-      (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach((d) => visible[d.id] = true);
-      const currSource = baseLayer.source();
-      const osm = context.connection();
-      const blocklists = osm && osm.imageryBlocklists() || [];
-      const blocklistChanged = blocklists.length !== _checkedBlocklists.length || blocklists.some((regex, index) => String(regex) !== _checkedBlocklists[index]);
-      if (blocklistChanged) {
-        _imageryIndex.backgrounds.forEach((source) => {
-          source.isBlocked = blocklists.some((regex) => regex.test(source.template()));
+      if (entity.tags.email) {
+        var emails = entity.tags.email.split(";").map(function(s2) {
+          return s2.trim();
+        }).filter(function(x2) {
+          return !isValidEmail(x2);
         });
-        _checkedBlocklists = blocklists.map((regex) => String(regex));
+        if (emails.length) {
+          issues.push(new validationIssue({
+            type: type2,
+            subtype: "email",
+            severity: "warning",
+            message: function(context) {
+              var entity2 = context.hasEntity(this.entityIds[0]);
+              return entity2 ? _t.append(
+                "issues.invalid_format.email.message" + this.data,
+                { feature: utilDisplayLabel(entity2, context.graph()), email: emails.join(", ") }
+              ) : "";
+            },
+            reference: showReferenceEmail,
+            entityIds: [entity.id],
+            hash: emails.join(),
+            data: emails.length > 1 ? "_multi" : ""
+          }));
+        }
       }
-      return _imageryIndex.backgrounds.filter((source) => {
-        if (includeCurrent && currSource === source)
-          return true;
-        if (source.isBlocked)
-          return false;
-        if (!source.polygon)
-          return true;
-        if (zoom && zoom < 6)
-          return false;
-        return visible[source.id];
-      });
-    };
-    background.dimensions = (val) => {
-      if (!val)
-        return;
-      baseLayer.dimensions(val);
-      _overlayLayers.forEach((layer) => layer.dimensions(val));
+      return issues;
     };
-    background.baseLayerSource = function(d) {
-      if (!arguments.length)
-        return baseLayer.source();
-      const osm = context.connection();
-      if (!osm)
-        return background;
-      const blocklists = osm.imageryBlocklists();
-      const template = d.template();
-      let fail = false;
-      let tested = 0;
-      let regex;
-      for (let i2 = 0; i2 < blocklists.length; i2++) {
-        regex = blocklists[i2];
-        fail = regex.test(template);
-        tested++;
-        if (fail)
-          break;
+    validation.type = type2;
+    return validation;
+  }
+
+  // modules/validations/help_request.js
+  function validationHelpRequest(context) {
+    var type2 = "help_request";
+    var validation = function checkFixmeTag(entity) {
+      if (!entity.tags.fixme) return [];
+      if (entity.version === void 0) return [];
+      if (entity.v !== void 0) {
+        var baseEntity = context.history().base().hasEntity(entity.id);
+        if (!baseEntity || !baseEntity.tags.fixme) return [];
       }
-      if (!tested) {
-        regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
-        fail = regex.test(template);
+      return [new validationIssue({
+        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
+              /* verbose */
+            )
+          }) : "";
+        },
+        dynamicFixes: function() {
+          return [
+            new validationIssueFix({
+              title: _t.append("issues.fix.address_the_concern.title")
+            })
+          ];
+        },
+        reference: showReference,
+        entityIds: [entity.id]
+      })];
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.fixme_tag.reference"));
       }
-      baseLayer.source(!fail ? d : background.findSource("none"));
-      dispatch10.call("change");
-      background.updateImagery();
-      return background;
     };
-    background.findSource = (id2) => {
-      if (!id2 || !_imageryIndex)
+    validation.type = type2;
+    return validation;
+  }
+
+  // modules/validations/impossible_oneway.js
+  function validationImpossibleOneway() {
+    var type2 = "impossible_oneway";
+    var validation = function checkImpossibleOneway(entity, graph) {
+      if (entity.type !== "way" || entity.geometry(graph) !== "line") return [];
+      if (entity.isClosed()) return [];
+      if (!typeForWay(entity)) return [];
+      if (!isOneway(entity)) return [];
+      var firstIssues = issuesForNode(entity, entity.first());
+      var lastIssues = issuesForNode(entity, entity.last());
+      return firstIssues.concat(lastIssues);
+      function typeForWay(way) {
+        if (way.geometry(graph) !== "line") return null;
+        if (osmRoutableHighwayTagValues[way.tags.highway]) return "highway";
+        if (osmFlowingWaterwayTagValues[way.tags.waterway]) return "waterway";
         return null;
-      return _imageryIndex.backgrounds.find((d) => d.id && d.id === id2);
-    };
-    background.bing = () => {
-      background.baseLayerSource(background.findSource("Bing"));
-    };
-    background.showsLayer = (d) => {
-      const currSource = baseLayer.source();
-      if (!d || !currSource)
-        return false;
-      return d.id === currSource.id || _overlayLayers.some((layer) => d.id === layer.source().id);
-    };
-    background.overlayLayerSources = () => {
-      return _overlayLayers.map((layer) => layer.source());
-    };
-    background.toggleOverlayLayer = (d) => {
-      let layer;
-      for (let i2 = 0; i2 < _overlayLayers.length; i2++) {
-        layer = _overlayLayers[i2];
-        if (layer.source() === d) {
-          _overlayLayers.splice(i2, 1);
-          dispatch10.call("change");
-          background.updateImagery();
-          return;
-        }
-      }
-      layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(
-        baseLayer.dimensions()
-      );
-      _overlayLayers.push(layer);
-      dispatch10.call("change");
-      background.updateImagery();
-    };
-    background.nudge = (d, zoom) => {
-      const currSource = baseLayer.source();
-      if (currSource) {
-        currSource.nudge(d, zoom);
-        dispatch10.call("change");
-        background.updateImagery();
-      }
-      return background;
-    };
-    background.offset = function(d) {
-      const currSource = baseLayer.source();
-      if (!arguments.length) {
-        return currSource && currSource.offset() || [0, 0];
-      }
-      if (currSource) {
-        currSource.offset(d);
-        dispatch10.call("change");
-        background.updateImagery();
       }
-      return background;
-    };
-    background.brightness = function(d) {
-      if (!arguments.length)
-        return _brightness;
-      _brightness = d;
-      if (context.mode())
-        dispatch10.call("change");
-      return background;
-    };
-    background.contrast = function(d) {
-      if (!arguments.length)
-        return _contrast;
-      _contrast = d;
-      if (context.mode())
-        dispatch10.call("change");
-      return background;
-    };
-    background.saturation = function(d) {
-      if (!arguments.length)
-        return _saturation;
-      _saturation = d;
-      if (context.mode())
-        dispatch10.call("change");
-      return background;
-    };
-    background.sharpness = function(d) {
-      if (!arguments.length)
-        return _sharpness;
-      _sharpness = d;
-      if (context.mode())
-        dispatch10.call("change");
-      return background;
-    };
-    let _loadPromise;
-    background.ensureLoaded = () => {
-      if (_loadPromise)
-        return _loadPromise;
-      return _loadPromise = ensureImageryIndex();
-    };
-    background.init = () => {
-      const loadPromise = background.ensureLoaded();
-      const hash = utilStringQs(window.location.hash);
-      const requestedBackground = hash.background || hash.layer;
-      const lastUsedBackground = corePreferences("background-last-used");
-      return loadPromise.then((imageryIndex) => {
-        const extent = context.map().extent();
-        const validBackgrounds = background.sources(extent).filter((d) => d.id !== "none" && d.id !== "custom");
-        const first = validBackgrounds.length && validBackgrounds[0];
-        const isLastUsedValid = !!validBackgrounds.find((d) => d.id && d.id === lastUsedBackground);
-        let best;
-        if (!requestedBackground && extent) {
-          best = validBackgrounds.find((s) => s.best());
-        }
-        if (requestedBackground && requestedBackground.indexOf("custom:") === 0) {
-          const template = requestedBackground.replace(/^custom:/, "");
-          const custom = background.findSource("custom");
-          background.baseLayerSource(custom.template(template));
-          corePreferences("background-custom-template", template);
-        } else {
-          background.baseLayerSource(
-            background.findSource(requestedBackground) || best || isLastUsedValid && background.findSource(lastUsedBackground) || background.findSource("Bing") || first || background.findSource("none")
-          );
-        }
-        const locator = imageryIndex.backgrounds.find((d) => d.overlay && d.default);
-        if (locator) {
-          background.toggleOverlayLayer(locator);
-        }
-        const overlays = (hash.overlays || "").split(",");
-        overlays.forEach((overlay) => {
-          overlay = background.findSource(overlay);
-          if (overlay) {
-            background.toggleOverlayLayer(overlay);
+      function isOneway(way) {
+        if (way.tags.oneway === "yes") return true;
+        if (way.tags.oneway) return false;
+        for (var key in way.tags) {
+          if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
+            return true;
           }
-        });
-        if (hash.gpx) {
-          const gpx2 = context.layers().layer("data");
-          if (gpx2) {
-            gpx2.url(hash.gpx, ".gpx");
+        }
+        return false;
+      }
+      function nodeOccursMoreThanOnce(way, nodeID) {
+        var occurrences = 0;
+        for (var index in way.nodes) {
+          if (way.nodes[index] === nodeID) {
+            occurrences += 1;
+            if (occurrences > 1) return true;
           }
         }
-        if (hash.offset) {
-          const offset = hash.offset.replace(/;/g, ",").split(",").map((n2) => !isNaN(n2) && n2);
-          if (offset.length === 2) {
-            background.offset(geoMetersToOffset(offset));
+        return false;
+      }
+      function isConnectedViaOtherTypes(way, node) {
+        var wayType = typeForWay(way);
+        if (wayType === "highway") {
+          if (node.tags.entrance && node.tags.entrance !== "no") return true;
+          if (node.tags.amenity === "parking_entrance") return true;
+        } else if (wayType === "waterway") {
+          if (node.id === way.first()) {
+            if (node.tags.natural === "spring") return true;
+          } else {
+            if (node.tags.manhole === "drain") return true;
           }
         }
-      }).catch((err) => {
-        console.error(err);
-      });
-    };
-    return utilRebind(background, dispatch10, "on");
-  }
-
-  // modules/renderer/features.js
-  function rendererFeatures(context) {
-    var dispatch10 = dispatch_default("change", "redraw");
-    var features2 = utilRebind({}, dispatch10, "on");
-    var _deferred2 = /* @__PURE__ */ new Set();
-    var traffic_roads = {
-      "motorway": true,
-      "motorway_link": true,
-      "trunk": true,
-      "trunk_link": true,
-      "primary": true,
-      "primary_link": true,
-      "secondary": true,
-      "secondary_link": true,
-      "tertiary": true,
-      "tertiary_link": true,
-      "residential": true,
-      "unclassified": true,
-      "living_street": true
-    };
-    var service_roads = {
-      "service": true,
-      "road": true,
-      "track": true
-    };
-    var paths = {
-      "path": true,
-      "footway": true,
-      "cycleway": true,
-      "bridleway": true,
-      "steps": true,
-      "pedestrian": true
-    };
-    var _cullFactor = 1;
-    var _cache4 = {};
-    var _rules = {};
-    var _stats = {};
-    var _keys = [];
-    var _hidden = [];
-    var _forceVisible = {};
-    function update() {
-      if (!window.mocha) {
-        var hash = utilStringQs(window.location.hash);
-        var disabled = features2.disabled();
-        if (disabled.length) {
-          hash.disable_features = disabled.join(",");
+        return graph.parentWays(node).some(function(parentWay) {
+          if (parentWay.id === way.id) return false;
+          if (wayType === "highway") {
+            if (parentWay.geometry(graph) === "area" && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true;
+            if (parentWay.tags.route === "ferry") return true;
+            return graph.parentRelations(parentWay).some(function(parentRelation) {
+              if (parentRelation.tags.type === "route" && parentRelation.tags.route === "ferry") return true;
+              return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
+            });
+          } else if (wayType === "waterway") {
+            if (parentWay.tags.natural === "water" || parentWay.tags.natural === "coastline") return true;
+          }
+          return false;
+        });
+      }
+      function issuesForNode(way, nodeID) {
+        var isFirst = nodeID === way.first();
+        var wayType = typeForWay(way);
+        if (nodeOccursMoreThanOnce(way, nodeID)) return [];
+        var osm = services.osm;
+        if (!osm) return [];
+        var node = graph.hasEntity(nodeID);
+        if (!node || !osm.isDataLoaded(node.loc)) return [];
+        if (isConnectedViaOtherTypes(way, node)) return [];
+        var attachedWaysOfSameType = graph.parentWays(node).filter(function(parentWay) {
+          if (parentWay.id === way.id) return false;
+          return typeForWay(parentWay) === wayType;
+        });
+        if (wayType === "waterway" && attachedWaysOfSameType.length === 0) return [];
+        var attachedOneways = attachedWaysOfSameType.filter(function(attachedWay) {
+          return isOneway(attachedWay);
+        });
+        if (attachedOneways.length < attachedWaysOfSameType.length) return [];
+        if (attachedOneways.length) {
+          var connectedEndpointsOkay = attachedOneways.some(function(attachedOneway) {
+            if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
+            if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
+            return false;
+          });
+          if (connectedEndpointsOkay) return [];
+        }
+        var placement = isFirst ? "start" : "end", messageID = wayType + ".", referenceID = wayType + ".";
+        if (wayType === "waterway") {
+          messageID += "connected." + placement;
+          referenceID += "connected";
         } else {
-          delete hash.disable_features;
+          messageID += placement;
+          referenceID += placement;
         }
-        window.location.replace("#" + utilQsString(hash, true));
-        corePreferences("disabled-features", disabled.join(","));
-      }
-      _hidden = features2.hidden();
-      dispatch10.call("change");
-      dispatch10.call("redraw");
-    }
-    function defineRule(k, filter2, max3) {
-      var isEnabled = true;
-      _keys.push(k);
-      _rules[k] = {
-        filter: filter2,
-        enabled: isEnabled,
-        count: 0,
-        currentMax: max3 || Infinity,
-        defaultMax: max3 || Infinity,
-        enable: function() {
-          this.enabled = true;
-          this.currentMax = this.defaultMax;
-        },
-        disable: function() {
-          this.enabled = false;
-          this.currentMax = 0;
-        },
-        hidden: function() {
-          return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
-        },
-        autoHidden: function() {
-          return this.hidden() && this.currentMax > 0;
+        return [new validationIssue({
+          type: type2,
+          subtype: wayType,
+          severity: "warning",
+          message: function(context) {
+            var entity2 = context.hasEntity(this.entityIds[0]);
+            return entity2 ? _t.append("issues.impossible_oneway." + messageID + ".message", {
+              feature: utilDisplayLabel(entity2, context.graph())
+            }) : "";
+          },
+          reference: getReference(referenceID),
+          entityIds: [way.id, node.id],
+          dynamicFixes: function() {
+            var fixes = [];
+            if (attachedOneways.length) {
+              fixes.push(new validationIssueFix({
+                icon: "iD-operation-reverse",
+                title: _t.append("issues.fix.reverse_feature.title"),
+                entityIds: [way.id],
+                onClick: function(context) {
+                  var id2 = this.issue.entityIds[0];
+                  context.perform(actionReverse(id2), _t("operations.reverse.annotation.line", { n: 1 }));
+                }
+              }));
+            }
+            if (node.tags.noexit !== "yes") {
+              var textDirection = _mainLocalizer.textDirection();
+              var useLeftContinue = isFirst && textDirection === "ltr" || !isFirst && textDirection === "rtl";
+              fixes.push(new validationIssueFix({
+                icon: "iD-operation-continue" + (useLeftContinue ? "-left" : ""),
+                title: _t.append("issues.fix.continue_from_" + (isFirst ? "start" : "end") + ".title"),
+                onClick: function(context) {
+                  var entityID = this.issue.entityIds[0];
+                  var vertexID = this.issue.entityIds[1];
+                  var way2 = context.entity(entityID);
+                  var vertex = context.entity(vertexID);
+                  continueDrawing(way2, vertex, context);
+                }
+              }));
+            }
+            return fixes;
+          },
+          loc: node.loc
+        })];
+        function getReference(referenceID2) {
+          return function showReference(selection2) {
+            selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.impossible_oneway." + referenceID2 + ".reference"));
+          };
         }
-      };
-    }
-    defineRule("points", function isPoint(tags, geometry) {
-      return geometry === "point";
-    }, 200);
-    defineRule("traffic_roads", function isTrafficRoad(tags) {
-      return traffic_roads[tags.highway];
-    });
-    defineRule("service_roads", function isServiceRoad(tags) {
-      return service_roads[tags.highway];
-    });
-    defineRule("paths", function isPath(tags) {
-      return paths[tags.highway];
-    });
-    defineRule("buildings", function isBuilding(tags) {
-      return !!tags.building && tags.building !== "no" || tags.parking === "multi-storey" || tags.parking === "sheds" || tags.parking === "carports" || tags.parking === "garage_boxes";
-    }, 250);
-    defineRule("building_parts", function isBuildingPart(tags) {
-      return tags["building:part"];
-    });
-    defineRule("indoor", function isIndoor(tags) {
-      return tags.indoor;
-    });
-    defineRule("landuse", function isLanduse(tags, geometry) {
-      return geometry === "area" && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
-    });
-    defineRule("boundaries", function isBoundary(tags, geometry) {
-      return (geometry === "line" && !!tags.boundary || geometry === "relation" && tags.type === "boundary") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway] || tags.waterway || tags.railway || tags.landuse || tags.natural || tags.building || tags.power);
-    });
-    defineRule("water", function isWater(tags) {
-      return !!tags.waterway || tags.natural === "water" || tags.natural === "coastline" || tags.natural === "bay" || tags.landuse === "pond" || tags.landuse === "basin" || tags.landuse === "reservoir" || tags.landuse === "salt_pond";
-    });
-    defineRule("rail", function isRail(tags) {
-      return (!!tags.railway || tags.landuse === "railway") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
-    });
-    defineRule("pistes", function isPiste(tags) {
-      return tags["piste:type"];
-    });
-    defineRule("aerialways", function isPiste(tags) {
-      return tags.aerialway && tags.aerialway !== "yes" && tags.aerialway !== "station";
-    });
-    defineRule("power", function isPower(tags) {
-      return !!tags.power;
-    });
-    defineRule("past_future", function isPastFuture(tags) {
-      if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
-        return false;
-      }
-      var strings = Object.keys(tags);
-      for (var i2 = 0; i2 < strings.length; i2++) {
-        var s = strings[i2];
-        if (osmLifecyclePrefixes[s] || osmLifecyclePrefixes[tags[s]])
-          return true;
       }
-      return false;
-    });
-    defineRule("others", function isOther(tags, geometry) {
-      return geometry === "line" || geometry === "area";
-    });
-    features2.features = function() {
-      return _rules;
-    };
-    features2.keys = function() {
-      return _keys;
     };
-    features2.enabled = function(k) {
-      if (!arguments.length) {
-        return _keys.filter(function(k2) {
-          return _rules[k2].enabled;
-        });
+    function continueDrawing(way, vertex, context) {
+      var map2 = context.map();
+      if (!context.editable() || !map2.trimmedExtent().contains(vertex.loc)) {
+        map2.zoomToEase(vertex);
       }
-      return _rules[k] && _rules[k].enabled;
-    };
-    features2.disabled = function(k) {
-      if (!arguments.length) {
-        return _keys.filter(function(k2) {
-          return !_rules[k2].enabled;
-        });
+      context.enter(
+        modeDrawLine(context, way.id, context.graph(), "line", way.affix(vertex.id), true)
+      );
+    }
+    validation.type = type2;
+    return validation;
+  }
+
+  // modules/validations/incompatible_source.js
+  function validationIncompatibleSource() {
+    const type2 = "incompatible_source";
+    const incompatibleRules = [
+      {
+        id: "amap",
+        regex: /(^amap$|^amap\.com|autonavi|mapabc|高德)/i
+      },
+      {
+        id: "baidu",
+        regex: /(baidu|mapbar|百度)/i
+      },
+      {
+        id: "google",
+        regex: /google/i,
+        exceptRegex: /((books|drive)\.google|google\s?(books|drive|plus))|(esri\/Google_Africa_Buildings)/i
       }
-      return _rules[k] && !_rules[k].enabled;
-    };
-    features2.hidden = function(k) {
-      if (!arguments.length) {
-        return _keys.filter(function(k2) {
-          return _rules[k2].hidden();
+    ];
+    const validation = function checkIncompatibleSource(entity) {
+      const entitySources = entity.tags && entity.tags.source && entity.tags.source.split(";");
+      if (!entitySources) return [];
+      const entityID = entity.id;
+      return entitySources.map((source) => {
+        const matchRule = incompatibleRules.find((rule) => {
+          if (!rule.regex.test(source)) return false;
+          if (rule.exceptRegex && rule.exceptRegex.test(source)) return false;
+          return true;
         });
-      }
-      return _rules[k] && _rules[k].hidden();
-    };
-    features2.autoHidden = function(k) {
-      if (!arguments.length) {
-        return _keys.filter(function(k2) {
-          return _rules[k2].autoHidden();
+        if (!matchRule) return null;
+        return new validationIssue({
+          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
+                /* verbose */
+              ),
+              value: source
+            }) : "";
+          },
+          reference: getReference(matchRule.id),
+          entityIds: [entityID],
+          hash: source,
+          dynamicFixes: () => {
+            return [
+              new validationIssueFix({ title: _t.append("issues.fix.remove_proprietary_data.title") })
+            ];
+          }
         });
+      }).filter(Boolean);
+      function getReference(id2) {
+        return function showReference(selection2) {
+          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.incompatible_source.reference.".concat(id2)));
+        };
       }
-      return _rules[k] && _rules[k].autoHidden();
-    };
-    features2.enable = function(k) {
-      if (_rules[k] && !_rules[k].enabled) {
-        _rules[k].enable();
-        update();
-      }
-    };
-    features2.enableAll = function() {
-      var didEnable = false;
-      for (var k in _rules) {
-        if (!_rules[k].enabled) {
-          didEnable = true;
-          _rules[k].enable();
-        }
-      }
-      if (didEnable)
-        update();
-    };
-    features2.disable = function(k) {
-      if (_rules[k] && _rules[k].enabled) {
-        _rules[k].disable();
-        update();
-      }
-    };
-    features2.disableAll = function() {
-      var didDisable = false;
-      for (var k in _rules) {
-        if (_rules[k].enabled) {
-          didDisable = true;
-          _rules[k].disable();
-        }
-      }
-      if (didDisable)
-        update();
     };
-    features2.toggle = function(k) {
-      if (_rules[k]) {
-        (function(f2) {
-          return f2.enabled ? f2.disable() : f2.enable();
-        })(_rules[k]);
-        update();
+    validation.type = type2;
+    return validation;
+  }
+
+  // modules/validations/maprules.js
+  function validationMaprules() {
+    var type2 = "maprules";
+    var validation = function checkMaprules(entity, graph) {
+      if (!services.maprules) return [];
+      var rules = services.maprules.validationRules();
+      var issues = [];
+      for (var i3 = 0; i3 < rules.length; i3++) {
+        var rule = rules[i3];
+        rule.findIssues(entity, graph, issues);
       }
+      return issues;
     };
-    features2.resetStats = function() {
-      for (var i2 = 0; i2 < _keys.length; i2++) {
-        _rules[_keys[i2]].count = 0;
+    validation.type = type2;
+    return validation;
+  }
+
+  // modules/validations/mismatched_geometry.js
+  var import_fast_deep_equal4 = __toESM(require_fast_deep_equal());
+  function validationMismatchedGeometry() {
+    var type2 = "mismatched_geometry";
+    function tagSuggestingLineIsArea(entity) {
+      if (entity.type !== "way" || entity.isClosed()) return null;
+      var tagSuggestingArea = entity.tagSuggestingArea();
+      if (!tagSuggestingArea) {
+        return null;
       }
-      dispatch10.call("change");
-    };
-    features2.gatherStats = function(d, resolver, dimensions) {
-      var needsRedraw = false;
-      var types = utilArrayGroupBy(d, "type");
-      var entities = [].concat(types.relation || [], types.way || [], types.node || []);
-      var currHidden, geometry, matches, i2, j2;
-      for (i2 = 0; i2 < _keys.length; i2++) {
-        _rules[_keys[i2]].count = 0;
+      var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, "line");
+      var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, "area");
+      if (asLine && asArea && (0, import_fast_deep_equal4.default)(asLine.tags, asArea.tags)) {
+        return null;
       }
-      _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));
-        for (j2 = 0; j2 < matches.length; j2++) {
-          _rules[matches[j2]].count++;
+      return tagSuggestingArea;
+    }
+    function makeConnectEndpointsFixOnClick(way, graph) {
+      if (way.nodes.length < 3) return null;
+      var nodes = graph.childNodes(way), testNodes;
+      var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc);
+      if (firstToLastDistanceMeters < 0.75) {
+        testNodes = nodes.slice();
+        testNodes.pop();
+        testNodes.push(testNodes[0]);
+        if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
+          return function(context) {
+            var way2 = context.entity(this.issue.entityIds[0]);
+            context.perform(
+              actionMergeNodes([way2.nodes[0], way2.nodes[way2.nodes.length - 1]], nodes[0].loc),
+              _t("issues.fix.connect_endpoints.annotation")
+            );
+          };
         }
       }
-      currHidden = features2.hidden();
-      if (currHidden !== _hidden) {
-        _hidden = currHidden;
-        needsRedraw = true;
-        dispatch10.call("change");
-      }
-      return needsRedraw;
-    };
-    features2.stats = function() {
-      for (var i2 = 0; i2 < _keys.length; i2++) {
-        _stats[_keys[i2]] = _rules[_keys[i2]].count;
-      }
-      return _stats;
-    };
-    features2.clear = function(d) {
-      for (var i2 = 0; i2 < d.length; i2++) {
-        features2.clearEntity(d[i2]);
+      testNodes = nodes.slice();
+      testNodes.push(testNodes[0]);
+      if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
+        return function(context) {
+          var wayId = this.issue.entityIds[0];
+          var way2 = context.entity(wayId);
+          var nodeId = way2.nodes[0];
+          var index = way2.nodes.length;
+          context.perform(
+            actionAddVertex(wayId, nodeId, index),
+            _t("issues.fix.connect_endpoints.annotation")
+          );
+        };
       }
-    };
-    features2.clearEntity = function(entity) {
-      delete _cache4[osmEntity.key(entity)];
-    };
-    features2.reset = function() {
-      Array.from(_deferred2).forEach(function(handle) {
-        window.cancelIdleCallback(handle);
-        _deferred2.delete(handle);
-      });
-      _cache4 = {};
-    };
-    function relationShouldBeChecked(relation) {
-      return relation.tags.type === "boundary";
     }
-    features2.getMatches = function(entity, resolver, geometry) {
-      if (geometry === "vertex" || geometry === "relation" && !relationShouldBeChecked(entity))
-        return {};
-      var ent = osmEntity.key(entity);
-      if (!_cache4[ent]) {
-        _cache4[ent] = {};
-      }
-      if (!_cache4[ent].matches) {
-        var matches = {};
-        var hasMatch = false;
-        for (var i2 = 0; i2 < _keys.length; i2++) {
-          if (_keys[i2] === "others") {
-            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) {
-                return parent.tags.type === "boundary";
-              })) {
-                var pkey = osmEntity.key(parents[0]);
-                if (_cache4[pkey] && _cache4[pkey].matches) {
-                  matches = Object.assign({}, _cache4[pkey].matches);
-                  continue;
-                }
-              }
-            }
-          }
-          if (_rules[_keys[i2]].filter(entity.tags, geometry)) {
-            matches[_keys[i2]] = hasMatch = true;
-          }
+    function lineTaggedAsAreaIssue(entity) {
+      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;
         }
-        _cache4[ent].matches = matches;
-      }
-      return _cache4[ent].matches;
-    };
-    features2.getParents = function(entity, resolver, geometry) {
-      if (geometry === "point")
-        return [];
-      var ent = osmEntity.key(entity);
-      if (!_cache4[ent]) {
-        _cache4[ent] = {};
-      }
-      if (!_cache4[ent].parents) {
-        var parents = [];
-        if (geometry === "vertex") {
-          parents = resolver.parentWays(entity);
-        } else {
-          parents = resolver.parentRelations(entity);
+        if (Object.keys(presetAsLine.tags).length === 0) {
+          validAsLine = false;
         }
-        _cache4[ent].parents = parents;
       }
-      return _cache4[ent].parents;
-    };
-    features2.isHiddenPreset = function(preset, geometry) {
-      if (!_hidden.length)
-        return false;
-      if (!preset.tags)
-        return false;
-      var test = preset.setTags({}, geometry);
-      for (var key in _rules) {
-        if (_rules[key].filter(test, geometry)) {
-          if (_hidden.indexOf(key) !== -1) {
-            return key;
+      return new validationIssue({
+        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
+              /* verbose */
+            ),
+            tag: utilTagText({ tags: tagSuggestingArea })
+          }) : "";
+        },
+        reference: showReference,
+        entityIds: [entity.id],
+        hash: JSON.stringify(tagSuggestingArea),
+        dynamicFixes: function(context) {
+          var fixes = [];
+          var entity2 = context.entity(this.entityIds[0]);
+          var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity2, context.graph());
+          if (!validAsLine) {
+            fixes.push(new validationIssueFix({
+              title: _t.append("issues.fix.connect_endpoints.title"),
+              onClick: connectEndsOnClick
+            }));
           }
-          return false;
+          fixes.push(new validationIssueFix({
+            icon: "iD-operation-delete",
+            title: _t.append("issues.fix.remove_tag.title"),
+            onClick: function(context2) {
+              var entityId = this.issue.entityIds[0];
+              var entity3 = context2.entity(entityId);
+              var tags = Object.assign({}, entity3.tags);
+              for (var key2 in tagSuggestingArea) {
+                delete tags[key2];
+              }
+              context2.perform(
+                actionChangeTags(entityId, tags),
+                _t("issues.fix.remove_tag.annotation")
+              );
+            }
+          }));
+          return fixes;
         }
-      }
-      return false;
-    };
-    features2.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));
-      return matches.length && matches.every(function(k) {
-        return features2.hidden(k);
       });
-    };
-    features2.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);
-      if (!parents.length)
-        return false;
-      for (var i2 = 0; i2 < parents.length; i2++) {
-        if (!features2.isHidden(parents[i2], resolver, parents[i2].geometry(resolver))) {
-          return false;
-        }
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.tag_suggests_area.reference"));
       }
-      return true;
-    };
-    features2.hasHiddenConnections = function(entity, resolver) {
-      if (!_hidden.length)
-        return false;
-      var childNodes, connections;
-      if (entity.type === "midpoint") {
-        childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
-        connections = [];
-      } else {
-        childNodes = entity.nodes ? resolver.childNodes(entity) : [];
-        connections = features2.getParents(entity, resolver, entity.geometry(resolver));
+    }
+    function vertexPointIssue(entity, graph) {
+      if (entity.type !== "node") return null;
+      if (Object.keys(entity.tags).length === 0) return null;
+      if (entity.isOnAddressLine(graph)) return null;
+      var geometry = entity.geometry(graph);
+      var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
+      if (geometry === "point" && !allowedGeometries.point && allowedGeometries.vertex) {
+        return new validationIssue({
+          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
+                /* verbose */
+              )
+            }) : "";
+          },
+          reference: function showReference(selection2) {
+            selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.vertex_as_point.reference"));
+          },
+          entityIds: [entity.id]
+        });
+      } else if (geometry === "vertex" && !allowedGeometries.vertex && allowedGeometries.point) {
+        return new validationIssue({
+          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
+                /* verbose */
+              )
+            }) : "";
+          },
+          reference: function showReference(selection2) {
+            selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.point_as_vertex.reference"));
+          },
+          entityIds: [entity.id],
+          dynamicFixes: extractPointDynamicFixes
+        });
       }
-      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 null;
+    }
+    function otherMismatchIssue(entity, graph) {
+      if (!entity.hasInterestingTags()) return null;
+      if (entity.type !== "node" && entity.type !== "way") return null;
+      if (entity.type === "node" && entity.isOnAddressLine(graph)) return null;
+      var sourceGeom = entity.geometry(graph);
+      var targetGeoms = entity.type === "way" ? ["point", "vertex"] : ["line", "area"];
+      if (sourceGeom === "area") targetGeoms.unshift("line");
+      var asSource = _mainPresetIndex.match(entity, graph);
+      var targetGeom = targetGeoms.find((nodeGeom) => {
+        var asTarget = _mainPresetIndex.matchTags(entity.tags, nodeGeom);
+        if (!asSource || !asTarget || asSource === asTarget || // sometimes there are two presets with the same tags for different geometries
+        (0, import_fast_deep_equal4.default)(asSource.tags, asTarget.tags)) return false;
+        if (asTarget.isFallback()) return false;
+        var primaryKey = Object.keys(asTarget.tags)[0];
+        if (primaryKey === "building") return false;
+        if (asTarget.tags[primaryKey] === "*") return false;
+        return asSource.isFallback() || asSource.tags[primaryKey] === "*";
       });
-    };
-    features2.isHidden = function(entity, resolver, geometry) {
-      if (!_hidden.length)
-        return false;
-      if (!entity.version)
-        return false;
-      var fn = geometry === "vertex" ? features2.isHiddenChild : features2.isHiddenFeature;
-      return fn(entity, resolver, geometry);
-    };
-    features2.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))) {
-          result.push(entity);
-        }
-      }
-      return result;
-    };
-    features2.forceVisible = function(entityIDs) {
-      if (!arguments.length)
-        return Object.keys(_forceVisible);
-      _forceVisible = {};
-      for (var i2 = 0; i2 < entityIDs.length; i2++) {
-        _forceVisible[entityIDs[i2]] = true;
-        var entity = context.hasEntity(entityIDs[i2]);
-        if (entity && entity.type === "relation") {
-          for (var j2 in entity.members) {
-            _forceVisible[entity.members[j2].id] = true;
+      if (!targetGeom) return null;
+      var subtype = targetGeom + "_as_" + sourceGeom;
+      if (targetGeom === "vertex") targetGeom = "point";
+      if (sourceGeom === "vertex") sourceGeom = "point";
+      var referenceId = targetGeom + "_as_" + sourceGeom;
+      var dynamicFixes;
+      if (targetGeom === "point") {
+        dynamicFixes = extractPointDynamicFixes;
+      } else if (sourceGeom === "area" && targetGeom === "line") {
+        dynamicFixes = lineToAreaDynamicFixes;
+      }
+      return new validationIssue({
+        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
+              /* verbose */
+            )
+          }) : "";
+        },
+        reference: function showReference(selection2) {
+          selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.mismatched_geometry.reference"));
+        },
+        entityIds: [entity.id],
+        dynamicFixes
+      });
+    }
+    function lineToAreaDynamicFixes(context) {
+      var convertOnClick;
+      var entityId = this.entityIds[0];
+      var entity = context.entity(entityId);
+      var tags = Object.assign({}, entity.tags);
+      delete tags.area;
+      if (!osmTagSuggestingArea(tags)) {
+        convertOnClick = function(context2) {
+          var entityId2 = this.issue.entityIds[0];
+          var entity2 = context2.entity(entityId2);
+          var tags2 = Object.assign({}, entity2.tags);
+          if (tags2.area) {
+            delete tags2.area;
           }
-        }
+          context2.perform(
+            actionChangeTags(entityId2, tags2),
+            _t("issues.fix.convert_to_line.annotation")
+          );
+        };
       }
-      return features2;
-    };
-    features2.init = function() {
-      var storage = corePreferences("disabled-features");
-      if (storage) {
-        var storageDisabled = storage.replace(/;/g, ",").split(",");
-        storageDisabled.forEach(features2.disable);
+      return [
+        new validationIssueFix({
+          icon: "iD-icon-line",
+          title: _t.append("issues.fix.convert_to_line.title"),
+          onClick: convertOnClick
+        })
+      ];
+    }
+    function extractPointDynamicFixes(context) {
+      var entityId = this.entityIds[0];
+      var extractOnClick = null;
+      if (!context.hasHiddenConnections(entityId)) {
+        extractOnClick = function(context2) {
+          var entityId2 = this.issue.entityIds[0];
+          var action = actionExtract(entityId2, context2.projection);
+          context2.perform(
+            action,
+            _t("operations.extract.annotation", { n: 1 })
+          );
+          context2.enter(modeSelect(context2, [action.getExtractedNodeID()]));
+        };
       }
-      var hash = utilStringQs(window.location.hash);
-      if (hash.disable_features) {
-        var hashDisabled = hash.disable_features.replace(/;/g, ",").split(",");
-        hashDisabled.forEach(features2.disable);
+      return [
+        new validationIssueFix({
+          icon: "iD-operation-extract",
+          title: _t.append("issues.fix.extract_point.title"),
+          onClick: extractOnClick
+        })
+      ];
+    }
+    function unclosedMultipolygonPartIssues(entity, 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 = [];
+      for (var i3 in sequences) {
+        var sequence = sequences[i3];
+        if (!sequence.nodes) continue;
+        var firstNode = sequence.nodes[0];
+        var lastNode = sequence.nodes[sequence.nodes.length - 1];
+        if (firstNode === lastNode) continue;
+        var issue = new validationIssue({
+          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
+                /* verbose */
+              )
+            }) : "";
+          },
+          reference: showReference,
+          loc: sequence.nodes[0].loc,
+          entityIds: [entity.id],
+          hash: sequence.map(function(way) {
+            return way.id;
+          }).join()
+        });
+        issues.push(issue);
+      }
+      return issues;
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.unclosed_multipolygon_part.reference"));
       }
+    }
+    var validation = function checkMismatchedGeometry(entity, graph) {
+      var vertexPoint = vertexPointIssue(entity, graph);
+      if (vertexPoint) return [vertexPoint];
+      var lineAsArea = lineTaggedAsAreaIssue(entity);
+      if (lineAsArea) return [lineAsArea];
+      var mismatch = otherMismatchIssue(entity, graph);
+      if (mismatch) return [mismatch];
+      return unclosedMultipolygonPartIssues(entity, graph);
     };
-    context.history().on("merge.features", function(newEntities) {
-      if (!newEntities)
-        return;
-      var handle = window.requestIdleCallback(function() {
-        var graph = context.graph();
-        var types = utilArrayGroupBy(newEntities, "type");
-        var entities = [].concat(types.relation || [], types.way || [], types.node || []);
-        for (var i2 = 0; i2 < entities.length; i2++) {
-          var geometry = entities[i2].geometry(graph);
-          features2.getMatches(entities[i2], graph, geometry);
-        }
-      });
-      _deferred2.add(handle);
-    });
-    return features2;
+    validation.type = type2;
+    return validation;
   }
 
-  // modules/svg/areas.js
-  var import_fast_deep_equal5 = __toESM(require_fast_deep_equal());
-
-  // modules/svg/helpers.js
-  function svgPassiveVertex(node, graph, activeID) {
-    if (!activeID)
-      return 1;
-    if (activeID === node.id)
-      return 0;
-    var parents = graph.parentWays(node);
-    var i2, j2, nodes, isClosed, ix1, ix2, ix3, ix4, max3;
-    for (i2 = 0; i2 < parents.length; i2++) {
-      nodes = parents[i2].nodes;
-      isClosed = parents[i2].isClosed();
-      for (j2 = 0; j2 < nodes.length; j2++) {
-        if (nodes[j2] === node.id) {
-          ix1 = j2 - 2;
-          ix2 = j2 - 1;
-          ix3 = j2 + 1;
-          ix4 = j2 + 2;
-          if (isClosed) {
-            max3 = nodes.length - 1;
-            if (ix1 < 0)
-              ix1 = max3 + ix1;
-            if (ix2 < 0)
-              ix2 = max3 + ix2;
-            if (ix3 > max3)
-              ix3 = ix3 - max3;
-            if (ix4 > max3)
-              ix4 = ix4 - max3;
-          }
-          if (nodes[ix1] === activeID)
-            return 0;
-          else if (nodes[ix2] === activeID)
-            return 2;
-          else if (nodes[ix3] === activeID)
-            return 2;
-          else if (nodes[ix4] === activeID)
-            return 0;
-          else if (isClosed && nodes.indexOf(activeID) !== -1)
-            return 0;
+  // modules/validations/missing_role.js
+  function validationMissingRole() {
+    var type2 = "missing_role";
+    var validation = function checkMissingRole(entity, graph) {
+      var issues = [];
+      if (entity.type === "way") {
+        graph.parentRelations(entity).forEach(function(relation) {
+          if (!relation.isMultipolygon()) return;
+          var member = relation.memberById(entity.id);
+          if (member && isMissingRole(member)) {
+            issues.push(makeIssue(entity, relation, member));
+          }
+        });
+      } else if (entity.type === "relation" && entity.isMultipolygon()) {
+        entity.indexedMembers().forEach(function(member) {
+          var way = graph.hasEntity(member.id);
+          if (way && isMissingRole(member)) {
+            issues.push(makeIssue(way, entity, member));
+          }
+        });
+      }
+      return issues;
+    };
+    function isMissingRole(member) {
+      return !member.role || !member.role.trim().length;
+    }
+    function makeIssue(way, relation, member) {
+      return new validationIssue({
+        type: type2,
+        severity: "warning",
+        message: function(context) {
+          var member2 = context.hasEntity(this.entityIds[1]), relation2 = context.hasEntity(this.entityIds[0]);
+          return member2 && relation2 ? _t.append("issues.missing_role.message", {
+            member: utilDisplayLabel(member2, context.graph()),
+            relation: utilDisplayLabel(relation2, context.graph())
+          }) : "";
+        },
+        reference: showReference,
+        entityIds: [relation.id, way.id],
+        data: {
+          member
+        },
+        hash: member.index.toString(),
+        dynamicFixes: function() {
+          return [
+            makeAddRoleFix("inner"),
+            makeAddRoleFix("outer"),
+            new validationIssueFix({
+              icon: "iD-operation-delete",
+              title: _t.append("issues.fix.remove_from_relation.title"),
+              onClick: function(context) {
+                context.perform(
+                  actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index),
+                  _t("operations.delete_member.annotation", {
+                    n: 1
+                  })
+                );
+              }
+            })
+          ];
         }
+      });
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.missing_role.multipolygon.reference"));
       }
     }
-    return 1;
+    function makeAddRoleFix(role) {
+      return new validationIssueFix({
+        title: _t.append("issues.fix.set_as_" + role + ".title"),
+        onClick: function(context) {
+          var oldMember = this.issue.data.member;
+          var member = { id: this.issue.entityIds[1], type: oldMember.type, role };
+          context.perform(
+            actionChangeMember(this.issue.entityIds[0], member, oldMember.index),
+            _t("operations.change_role.annotation", {
+              n: 1
+            })
+          );
+        }
+      });
+    }
+    validation.type = type2;
+    return validation;
   }
-  function svgMarkerSegments(projection2, graph, dt, shouldReverse, bothDirections) {
-    return function(entity) {
-      var i2 = 0;
-      var offset = dt;
-      var segments = [];
-      var clip = identity_default2().clipExtent(projection2.clipExtent()).stream;
-      var coordinates = graph.childNodes(entity).map(function(n2) {
-        return n2.loc;
+
+  // modules/validations/missing_tag.js
+  function validationMissingTag(context) {
+    var type2 = "missing_tag";
+    function hasDescriptiveTags(entity) {
+      var onlyAttributeKeys = ["description", "name", "note", "start_date"];
+      var entityDescriptiveKeys = Object.keys(entity.tags).filter(function(k2) {
+        if (k2 === "area" || !osmIsInterestingTag(k2)) return false;
+        return !onlyAttributeKeys.some(function(attributeKey) {
+          return k2 === attributeKey || k2.indexOf(attributeKey + ":") === 0;
+        });
       });
-      var a, b;
-      if (shouldReverse(entity)) {
-        coordinates.reverse();
+      if (entity.type === "relation" && entityDescriptiveKeys.length === 1 && entity.tags.type === "multipolygon") {
+        return false;
       }
-      stream_default({
-        type: "LineString",
-        coordinates
-      }, projection2.stream(clip({
-        lineStart: function() {
-        },
-        lineEnd: function() {
-          a = null;
+      return entityDescriptiveKeys.length > 0;
+    }
+    function isUnknownRoad(entity) {
+      return entity.type === "way" && entity.tags.highway === "road";
+    }
+    function isUntypedRelation(entity) {
+      return entity.type === "relation" && !entity.tags.type;
+    }
+    var validation = function checkMissingTag(entity, graph) {
+      var subtype;
+      var osm = context.connection();
+      var isUnloadedNode = entity.type === "node" && osm && !osm.isDataLoaded(entity.loc);
+      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)) {
+          subtype = "descriptive";
+        } else if (isUntypedRelation(entity)) {
+          subtype = "relation_type";
+        }
+      }
+      if (!subtype && isUnknownRoad(entity)) {
+        subtype = "highway_classification";
+      }
+      if (!subtype) return [];
+      var messageID = subtype === "highway_classification" ? "unknown_road" : "missing_tag." + subtype;
+      var referenceID = subtype === "highway_classification" ? "unknown_road" : "missing_tag";
+      var canDelete = entity.version === void 0 || entity.v !== void 0;
+      var severity = canDelete && subtype !== "highway_classification" ? "error" : "warning";
+      return [new validationIssue({
+        type: type2,
+        subtype,
+        severity,
+        message: function(context2) {
+          var entity2 = context2.hasEntity(this.entityIds[0]);
+          return entity2 ? _t.append("issues." + messageID + ".message", {
+            feature: utilDisplayLabel(entity2, context2.graph())
+          }) : "";
         },
-        point: function(x, y) {
-          b = [x, y];
-          if (a) {
-            var span = geoVecLength(a, b) - offset;
-            if (span >= 0) {
-              var heading = geoVecAngle(a, b);
-              var dx = dt * Math.cos(heading);
-              var dy = dt * Math.sin(heading);
-              var p = [
-                a[0] + offset * Math.cos(heading),
-                a[1] + offset * Math.sin(heading)
-              ];
-              var coord2 = [a, p];
-              for (span -= dt; span >= 0; span -= dt) {
-                p = geoVecAdd(p, [dx, dy]);
-                coord2.push(p);
-              }
-              coord2.push(b);
-              var segment = "";
-              var j2;
-              for (j2 = 0; j2 < coord2.length; j2++) {
-                segment += (j2 === 0 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
-              }
-              segments.push({ id: entity.id, index: i2++, d: segment });
-              if (bothDirections(entity)) {
-                segment = "";
-                for (j2 = coord2.length - 1; j2 >= 0; j2--) {
-                  segment += (j2 === coord2.length - 1 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
-                }
-                segments.push({ id: entity.id, index: i2++, d: segment });
-              }
+        reference: showReference,
+        entityIds: [entity.id],
+        dynamicFixes: function(context2) {
+          var fixes = [];
+          var selectFixType = subtype === "highway_classification" ? "select_road_type" : "select_preset";
+          fixes.push(new validationIssueFix({
+            icon: "iD-icon-search",
+            title: _t.append("issues.fix." + selectFixType + ".title"),
+            onClick: function(context3) {
+              context3.ui().sidebar.showPresetList();
             }
-            offset = -span;
+          }));
+          var deleteOnClick;
+          var id2 = this.entityIds[0];
+          var operation2 = operationDelete(context2, [id2]);
+          var disabledReasonID = operation2.disabled();
+          if (!disabledReasonID) {
+            deleteOnClick = function(context3) {
+              var id3 = this.issue.entityIds[0];
+              var operation3 = operationDelete(context3, [id3]);
+              if (!operation3.disabled()) {
+                operation3();
+              }
+            };
           }
-          a = b;
-        }
-      })));
-      return segments;
-    };
-  }
-  function svgPath(projection2, graph, isArea) {
-    var cache = {};
-    var padding = isArea ? 65 : 5;
-    var viewport = projection2.clipExtent();
-    var paddedExtent = [
-      [viewport[0][0] - padding, viewport[0][1] - padding],
-      [viewport[1][0] + padding, viewport[1][1] + padding]
-    ];
-    var clip = identity_default2().clipExtent(paddedExtent).stream;
-    var project = projection2.stream;
-    var path = path_default().projection({ stream: function(output) {
-      return project(clip(output));
-    } });
-    var svgpath = function(entity) {
-      if (entity.id in cache) {
-        return cache[entity.id];
-      } else {
-        return cache[entity.id] = path(entity.asGeoJSON(graph));
-      }
-    };
-    svgpath.geojson = function(d) {
-      if (d.__featurehash__ !== void 0) {
-        if (d.__featurehash__ in cache) {
-          return cache[d.__featurehash__];
-        } else {
-          return cache[d.__featurehash__] = path(d);
+          fixes.push(
+            new validationIssueFix({
+              icon: "iD-operation-delete",
+              title: _t.append("issues.fix.delete_feature.title"),
+              disabledReason: disabledReasonID ? _t("operations.delete." + disabledReasonID + ".single") : void 0,
+              onClick: deleteOnClick
+            })
+          );
+          return fixes;
         }
-      } else {
-        return path(d);
+      })];
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues." + referenceID + ".reference"));
       }
     };
-    return svgpath;
-  }
-  function svgPointTransform(projection2) {
-    var svgpoint = function(entity) {
-      var pt = projection2(entity.loc);
-      return "translate(" + pt[0] + "," + pt[1] + ")";
-    };
-    svgpoint.geojson = function(d) {
-      return svgpoint(d.properties.entity);
-    };
-    return svgpoint;
+    validation.type = type2;
+    return validation;
   }
-  function svgRelationMemberTags(graph) {
-    return function(entity) {
-      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") {
-          tags = Object.assign({}, relation.tags, tags);
-        }
+
+  // modules/validations/mutually_exclusive_tags.js
+  function validationMutuallyExclusiveTags() {
+    const type2 = "mutually_exclusive_tags";
+    const tagKeyPairs = osmMutuallyExclusiveTagPairs;
+    const validation = function checkMutuallyExclusiveTags(entity) {
+      let pairsFounds = tagKeyPairs.filter((pair3) => {
+        return pair3[0] in entity.tags && pair3[1] in entity.tags;
+      }).filter((pair3) => {
+        return !(pair3[0].match(/^(addr:)?no[a-z]/) && entity.tags[pair3[0]] === "no" || pair3[1].match(/^(addr:)?no[a-z]/) && entity.tags[pair3[1]] === "no");
       });
-      return tags;
-    };
-  }
-  function svgSegmentWay(way, graph, activeID) {
-    if (activeID === void 0) {
-      return graph.transient(way, "waySegments", getWaySegments);
-    } else {
-      return getWaySegments();
-    }
-    function getWaySegments() {
-      var isActiveWay = way.nodes.indexOf(activeID) !== -1;
-      var features2 = { passive: [], active: [] };
-      var start2 = {};
-      var end = {};
-      var node, type3;
-      for (var i2 = 0; i2 < way.nodes.length; i2++) {
-        node = graph.entity(way.nodes[i2]);
-        type3 = svgPassiveVertex(node, graph, activeID);
-        end = { node, type: type3 };
-        if (start2.type !== void 0) {
-          if (start2.node.id === activeID || end.node.id === activeID) {
-          } else if (isActiveWay && (start2.type === 2 || end.type === 2)) {
-            pushActive(start2, end, i2);
-          } else if (start2.type === 0 && end.type === 0) {
-            pushActive(start2, end, i2);
-          } else {
-            pushPassive(start2, end, i2);
+      Object.keys(entity.tags).forEach((key) => {
+        let negative_key = "not:" + key;
+        if (negative_key in entity.tags && entity.tags[negative_key].split(";").includes(entity.tags[key])) {
+          pairsFounds.push([negative_key, key, "same_value"]);
+        }
+        if (key.match(/^name:[a-z]+/)) {
+          negative_key = "not:name";
+          if (negative_key in entity.tags && entity.tags[negative_key].split(";").includes(entity.tags[key])) {
+            pairsFounds.push([negative_key, key, "same_value"]);
           }
         }
-        start2 = end;
-      }
-      return features2;
-      function pushActive(start3, end2, index) {
-        features2.active.push({
-          type: "Feature",
-          id: way.id + "-" + index + "-nope",
-          properties: {
-            nope: true,
-            target: true,
-            entity: way,
-            nodes: [start3.node, end2.node],
-            index
+      });
+      let issues = pairsFounds.map((pair3) => {
+        const subtype = pair3[2] || "default";
+        return new validationIssue({
+          type: type2,
+          subtype,
+          severity: "warning",
+          message: function(context) {
+            let entity2 = context.hasEntity(this.entityIds[0]);
+            return entity2 ? _t.append("issues.".concat(type2, ".").concat(subtype, ".message"), {
+              feature: utilDisplayLabel(entity2, context.graph()),
+              tag1: pair3[0],
+              tag2: pair3[1]
+            }) : "";
           },
-          geometry: {
-            type: "LineString",
-            coordinates: [start3.node.loc, end2.node.loc]
-          }
+          reference: (selection2) => showReference(selection2, pair3, subtype),
+          entityIds: [entity.id],
+          dynamicFixes: () => pair3.slice(0, 2).map((tagToRemove) => createIssueFix(tagToRemove))
         });
-      }
-      function pushPassive(start3, end2, index) {
-        features2.passive.push({
-          type: "Feature",
-          id: way.id + "-" + index,
-          properties: {
-            target: true,
-            entity: way,
-            nodes: [start3.node, end2.node],
-            index
-          },
-          geometry: {
-            type: "LineString",
-            coordinates: [start3.node.loc, end2.node.loc]
+      });
+      function createIssueFix(tagToRemove) {
+        return new validationIssueFix({
+          icon: "iD-operation-delete",
+          title: _t.append("issues.fix.remove_named_tag.title", { tag: tagToRemove }),
+          onClick: function(context) {
+            const entityId = this.issue.entityIds[0];
+            const entity2 = context.entity(entityId);
+            let tags = Object.assign({}, entity2.tags);
+            delete tags[tagToRemove];
+            context.perform(
+              actionChangeTags(entityId, tags),
+              _t("issues.fix.remove_named_tag.annotation", { tag: tagToRemove })
+            );
           }
         });
       }
-    }
+      function showReference(selection2, pair3, subtype) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.".concat(type2, ".").concat(subtype, ".reference"), { tag1: pair3[0], tag2: pair3[1] }));
+      }
+      return issues;
+    };
+    validation.type = type2;
+    return validation;
   }
 
-  // modules/svg/tag_classes.js
-  function svgTagClasses() {
-    var primaries = [
-      "building",
-      "highway",
-      "railway",
-      "waterway",
-      "aeroway",
-      "aerialway",
-      "piste:type",
-      "boundary",
-      "power",
-      "amenity",
-      "natural",
-      "landuse",
-      "leisure",
-      "military",
-      "place",
-      "man_made",
-      "route",
-      "attraction",
-      "building:part",
-      "indoor"
-    ];
-    var statuses = Object.keys(osmLifecyclePrefixes);
-    var secondaries = [
-      "oneway",
-      "bridge",
-      "tunnel",
-      "embankment",
-      "cutting",
-      "barrier",
-      "surface",
-      "tracktype",
-      "footway",
-      "crossing",
-      "service",
-      "sport",
-      "public_transport",
-      "location",
-      "parking",
-      "golf",
-      "type",
-      "leisure",
-      "man_made",
-      "indoor",
-      "construction",
-      "proposed"
-    ];
-    var _tags = function(entity) {
-      return entity.tags;
-    };
-    var tagClasses = function(selection2) {
-      selection2.each(function tagClassesEach(entity) {
-        var value = this.className;
-        if (value.baseVal !== void 0) {
-          value = value.baseVal;
-        }
-        var t = _tags(entity);
-        var computed = tagClasses.getClassesString(t, value);
-        if (computed !== value) {
-          select_default2(this).attr("class", computed);
+  // modules/validations/outdated_tags.js
+  function validationOutdatedTags() {
+    const type2 = "outdated_tags";
+    let _waitingForDeprecated = true;
+    let _dataDeprecated;
+    _mainFileFetcher.get("deprecated").then((d2) => _dataDeprecated = d2).catch(() => {
+    }).finally(() => _waitingForDeprecated = false);
+    function oldTagIssues(entity, graph) {
+      if (!entity.hasInterestingTags()) return [];
+      let preset = _mainPresetIndex.match(entity, graph);
+      if (!preset) 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
+          /* skip field defaults */
+        )(graph);
+        entity = graph.entity(entity.id);
+        preset = newPreset;
+      }
+      const upgradeReasons = [];
+      if (_dataDeprecated) {
+        const deprecatedTags = entity.deprecatedTags(_dataDeprecated);
+        if (entity.type === "way" && entity.isClosed() && entity.tags.traffic_calming === "island" && !entity.tags.highway) {
+          deprecatedTags.push({
+            old: { traffic_calming: "island" },
+            replace: { "area:highway": "traffic_island" }
+          });
         }
-      });
-    };
-    tagClasses.getClassesString = function(t, value) {
-      var primary, status;
-      var i2, j2, k, v;
-      var overrideGeometry;
-      if (/\bstroke\b/.test(value)) {
-        if (!!t.barrier && t.barrier !== "no") {
-          overrideGeometry = "line";
+        if (deprecatedTags.length) {
+          deprecatedTags.forEach((tag2) => {
+            graph = actionUpgradeTags(entity.id, tag2.old, tag2.replace)(graph);
+            upgradeReasons.push({
+              source: "id-tagging-schema--deprecated",
+              data: tag2
+            });
+          });
+          entity = graph.entity(entity.id);
         }
       }
-      var classes = value.trim().split(/\s+/).filter(function(klass) {
-        return klass.length && !/^tag-/.test(klass);
-      }).map(function(klass) {
-        return klass === "line" || klass === "area" ? overrideGeometry || klass : klass;
-      });
-      for (i2 = 0; i2 < primaries.length; i2++) {
-        k = primaries[i2];
-        v = t[k];
-        if (!v || v === "no")
-          continue;
-        if (k === "piste:type") {
-          k = "piste";
-        } else if (k === "building:part") {
-          k = "building_part";
-        }
-        primary = k;
-        if (statuses.indexOf(v) !== -1) {
-          status = v;
-          classes.push("tag-" + k);
-        } else {
-          classes.push("tag-" + k);
-          classes.push("tag-" + k + "-" + v);
+      let newTags = Object.assign({}, entity.tags);
+      if (preset.tags !== preset.addTags) {
+        Object.keys(preset.addTags).forEach((k2) => {
+          if (!newTags[k2]) {
+            if (preset.addTags[k2] === "*") {
+              newTags[k2] = "yes";
+            } else if (preset.addTags[k2]) {
+              newTags[k2] = preset.addTags[k2];
+            }
+            upgradeReasons.push({
+              source: "id-tagging-schema--preset-addTags",
+              data: preset
+            });
+          }
+        });
+      }
+      const nsi = services.nsi;
+      let waitingForNsi = false;
+      let nsiResult;
+      if (nsi) {
+        waitingForNsi = nsi.status() === "loading";
+        if (!waitingForNsi) {
+          const loc = entity.extent(graph).center();
+          nsiResult = nsi.upgradeTags(newTags, loc);
+          if (nsiResult) {
+            newTags = nsiResult.newTags;
+            subtype = "noncanonical_brand";
+            upgradeReasons.push({
+              source: "name-suggestion-index",
+              data: nsiResult
+            });
+          }
         }
-        break;
       }
-      if (!primary) {
-        for (i2 = 0; i2 < statuses.length; i2++) {
-          for (j2 = 0; j2 < primaries.length; j2++) {
-            k = statuses[i2] + ":" + primaries[j2];
-            v = t[k];
-            if (!v || v === "no")
-              continue;
-            status = statuses[i2];
-            break;
+      let issues = [];
+      issues.provisional = _waitingForDeprecated || waitingForNsi;
+      const tagDiff = utilTagDiff(oldTags, newTags);
+      if (!tagDiff.length) return issues;
+      const isOnlyAddingTags = tagDiff.every((d2) => d2.type === "+");
+      let prefix = "";
+      if (nsiResult) {
+        prefix = "noncanonical_brand.";
+      } else if (subtype === "deprecated_tags" && isOnlyAddingTags) {
+        subtype = "incomplete_tags";
+        prefix = "incomplete.";
+      }
+      let autoArgs = subtype !== "noncanonical_brand" ? [doUpgrade, _t("issues.fix.upgrade_tags.annotation")] : null;
+      issues.push(new validationIssue({
+        type: type2,
+        subtype,
+        severity: "warning",
+        message: showMessage,
+        reference: showReference,
+        entityIds: [entity.id],
+        hash: utilHashcode(JSON.stringify(tagDiff)),
+        dynamicFixes: () => {
+          let fixes = [
+            new validationIssueFix({
+              autoArgs,
+              title: _t.append("issues.fix.upgrade_tags.title"),
+              onClick: (context) => {
+                context.perform(doUpgrade, _t("issues.fix.upgrade_tags.annotation"));
+              }
+            })
+          ];
+          const item = nsiResult && nsiResult.matched;
+          if (item) {
+            fixes.push(
+              new validationIssueFix({
+                title: _t.append("issues.fix.tag_as_not.title", { name: item.displayName }),
+                onClick: (context) => {
+                  context.perform(addNotTag, _t("issues.fix.tag_as_not.annotation"));
+                }
+              })
+            );
           }
+          return fixes;
         }
+      }));
+      return issues;
+      function doUpgrade(graph2) {
+        const currEntity = graph2.hasEntity(entity.id);
+        if (!currEntity) return graph2;
+        let newTags2 = Object.assign({}, currEntity.tags);
+        tagDiff.forEach((diff) => {
+          if (diff.type === "-") {
+            delete newTags2[diff.key];
+          } else if (diff.type === "+") {
+            newTags2[diff.key] = diff.newVal;
+          }
+        });
+        return actionChangeTags(currEntity.id, newTags2)(graph2);
       }
-      if (!status) {
-        for (i2 = 0; i2 < statuses.length; i2++) {
-          k = statuses[i2];
-          v = t[k];
-          if (!v || v === "no")
-            continue;
-          if (v === "yes") {
-            status = k;
-          } else if (primary && primary === v) {
-            status = k;
-          } else if (!primary && primaries.indexOf(v) !== -1) {
-            status = k;
-            primary = v;
-            classes.push("tag-" + v);
-          }
-          if (status)
-            break;
+      function addNotTag(graph2) {
+        const currEntity = graph2.hasEntity(entity.id);
+        if (!currEntity) return graph2;
+        const item = nsiResult && nsiResult.matched;
+        if (!item) return graph2;
+        let newTags2 = Object.assign({}, currEntity.tags);
+        const wd = item.mainTag;
+        const notwd = "not:".concat(wd);
+        const qid = item.tags[wd];
+        newTags2[notwd] = qid;
+        if (newTags2[wd] === qid) {
+          const wp = item.mainTag.replace("wikidata", "wikipedia");
+          delete newTags2[wd];
+          delete newTags2[wp];
         }
+        return actionChangeTags(currEntity.id, newTags2)(graph2);
       }
-      if (status) {
-        classes.push("tag-status");
-        classes.push("tag-status-" + status);
+      function showMessage(context) {
+        const currEntity = context.hasEntity(entity.id);
+        if (!currEntity) return "";
+        let messageID = "issues.outdated_tags.".concat(prefix, "message");
+        if (subtype === "noncanonical_brand" && isOnlyAddingTags) {
+          messageID += "_incomplete";
+        }
+        return _t.append(messageID, {
+          feature: utilDisplayLabel(
+            currEntity,
+            context.graph(),
+            true
+            /* verbose */
+          )
+        });
       }
-      for (i2 = 0; i2 < secondaries.length; i2++) {
-        k = secondaries[i2];
-        v = t[k];
-        if (!v || v === "no" || k === primary)
-          continue;
-        classes.push("tag-" + k);
-        classes.push("tag-" + k + "-" + v);
+      function showReference(selection2) {
+        let enter = selection2.selectAll(".issue-reference").data([0]).enter();
+        enter.append("div").attr("class", "issue-reference").call(_t.append("issues.outdated_tags.".concat(prefix, "reference")));
+        enter.append("strong").call(_t.append("issues.suggested"));
+        enter.append("table").attr("class", "tagDiff-table").selectAll(".tagDiff-row").data(tagDiff).enter().append("tr").attr("class", "tagDiff-row").append("td").attr("class", (d2) => {
+          let klass = d2.type === "+" ? "add" : "remove";
+          return "tagDiff-cell tagDiff-cell-".concat(klass);
+        }).html((d2) => d2.display);
       }
-      if (primary === "highway" && !osmPathHighwayTagValues[t.highway] || primary === "aeroway") {
-        var surface = t.highway === "track" ? "unpaved" : "paved";
-        for (k in t) {
-          v = t[k];
-          if (k in osmPavedTags) {
-            surface = osmPavedTags[k][v] ? "paved" : "unpaved";
-          }
-          if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
-            surface = "semipaved";
-          }
+    }
+    let validation = oldTagIssues;
+    validation.type = type2;
+    return validation;
+  }
+
+  // modules/validations/private_data.js
+  function validationPrivateData() {
+    var type2 = "private_data";
+    var privateBuildingValues = {
+      detached: true,
+      farm: true,
+      house: true,
+      houseboat: true,
+      residential: true,
+      semidetached_house: true,
+      static_caravan: true
+    };
+    var publicKeys = {
+      amenity: true,
+      craft: true,
+      historic: true,
+      leisure: true,
+      office: true,
+      shop: true,
+      tourism: true
+    };
+    var personalTags = {
+      "contact:email": true,
+      "contact:fax": true,
+      "contact:phone": true,
+      email: true,
+      fax: true,
+      phone: true
+    };
+    var validation = function checkPrivateData(entity) {
+      var tags = entity.tags;
+      if (!tags.building || !privateBuildingValues[tags.building]) return [];
+      var keepTags = {};
+      for (var k2 in tags) {
+        if (publicKeys[k2]) return [];
+        if (!personalTags[k2]) {
+          keepTags[k2] = tags[k2];
         }
-        classes.push("tag-" + surface);
       }
-      var qid = t.wikidata || t["flag:wikidata"] || t["brand:wikidata"] || t["network:wikidata"] || t["operator:wikidata"];
-      if (qid) {
-        classes.push("tag-wikidata");
+      var tagDiff = utilTagDiff(tags, keepTags);
+      if (!tagDiff.length) return [];
+      var fixID = tagDiff.length === 1 ? "remove_tag" : "remove_tags";
+      return [new validationIssue({
+        type: type2,
+        severity: "warning",
+        message: showMessage,
+        reference: showReference,
+        entityIds: [entity.id],
+        dynamicFixes: function() {
+          return [
+            new validationIssueFix({
+              icon: "iD-operation-delete",
+              title: _t.append("issues.fix." + fixID + ".title"),
+              onClick: function(context) {
+                context.perform(doUpgrade, _t("issues.fix.remove_tag.annotation"));
+              }
+            })
+          ];
+        }
+      })];
+      function doUpgrade(graph) {
+        var currEntity = graph.hasEntity(entity.id);
+        if (!currEntity) return graph;
+        var newTags = Object.assign({}, currEntity.tags);
+        tagDiff.forEach(function(diff) {
+          if (diff.type === "-") {
+            delete newTags[diff.key];
+          } else if (diff.type === "+") {
+            newTags[diff.key] = diff.newVal;
+          }
+        });
+        return actionChangeTags(currEntity.id, newTags)(graph);
+      }
+      function showMessage(context) {
+        var currEntity = context.hasEntity(this.entityIds[0]);
+        if (!currEntity) return "";
+        return _t.append(
+          "issues.private_data.contact.message",
+          { feature: utilDisplayLabel(currEntity, context.graph()) }
+        );
+      }
+      function showReference(selection2) {
+        var enter = selection2.selectAll(".issue-reference").data([0]).enter();
+        enter.append("div").attr("class", "issue-reference").call(_t.append("issues.private_data.reference"));
+        enter.append("strong").call(_t.append("issues.suggested"));
+        enter.append("table").attr("class", "tagDiff-table").selectAll(".tagDiff-row").data(tagDiff).enter().append("tr").attr("class", "tagDiff-row").append("td").attr("class", function(d2) {
+          var klass = d2.type === "+" ? "add" : "remove";
+          return "tagDiff-cell tagDiff-cell-" + klass;
+        }).html(function(d2) {
+          return d2.display;
+        });
       }
-      return classes.join(" ").trim();
-    };
-    tagClasses.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
-      _tags = val;
-      return tagClasses;
     };
-    return tagClasses;
+    validation.type = type2;
+    return validation;
   }
 
-  // modules/svg/tag_pattern.js
-  var patterns = {
-    amenity: {
-      grave_yard: "cemetery",
-      fountain: "water_standing"
-    },
-    landuse: {
-      cemetery: [
-        { religion: "christian", pattern: "cemetery_christian" },
-        { religion: "buddhist", pattern: "cemetery_buddhist" },
-        { religion: "muslim", pattern: "cemetery_muslim" },
-        { religion: "jewish", pattern: "cemetery_jewish" },
-        { pattern: "cemetery" }
-      ],
-      construction: "construction",
-      farmland: "farmland",
-      farmyard: "farmyard",
-      forest: [
-        { leaf_type: "broadleaved", pattern: "forest_broadleaved" },
-        { leaf_type: "needleleaved", pattern: "forest_needleleaved" },
-        { leaf_type: "leafless", pattern: "forest_leafless" },
-        { pattern: "forest" }
-      ],
-      grave_yard: "cemetery",
-      grass: "grass",
-      landfill: "landfill",
-      meadow: "meadow",
-      military: "construction",
-      orchard: "orchard",
-      quarry: "quarry",
-      vineyard: "vineyard"
-    },
-    leisure: {
-      horse_riding: "farmyard"
-    },
-    natural: {
-      beach: "beach",
-      grassland: "grass",
-      sand: "beach",
-      scrub: "scrub",
-      water: [
-        { water: "pond", pattern: "pond" },
-        { water: "reservoir", pattern: "water_standing" },
-        { pattern: "waves" }
-      ],
-      wetland: [
-        { wetland: "marsh", pattern: "wetland_marsh" },
-        { wetland: "swamp", pattern: "wetland_swamp" },
-        { wetland: "bog", pattern: "wetland_bog" },
-        { wetland: "reedbed", pattern: "wetland_reedbed" },
-        { pattern: "wetland" }
-      ],
-      wood: [
-        { leaf_type: "broadleaved", pattern: "forest_broadleaved" },
-        { leaf_type: "needleleaved", pattern: "forest_needleleaved" },
-        { leaf_type: "leafless", pattern: "forest_leafless" },
-        { pattern: "forest" }
-      ]
-    },
-    golf: {
-      green: "golf_green",
-      tee: "grass",
-      fairway: "grass",
-      rough: "scrub"
-    },
-    surface: {
-      grass: "grass",
-      sand: "beach"
-    }
-  };
-  function svgTagPattern(tags) {
-    if (tags.building && tags.building !== "no") {
-      return null;
+  // modules/validations/suspicious_name.js
+  function validationSuspiciousName() {
+    const type2 = "suspicious_name";
+    const keysToTestForGenericValues = [
+      "aerialway",
+      "aeroway",
+      "amenity",
+      "building",
+      "craft",
+      "highway",
+      "leisure",
+      "railway",
+      "man_made",
+      "office",
+      "shop",
+      "tourism",
+      "waterway"
+    ];
+    let _waitingForNsi = false;
+    function isGenericMatchInNsi(tags) {
+      const nsi = services.nsi;
+      if (nsi) {
+        _waitingForNsi = nsi.status() === "loading";
+        if (!_waitingForNsi) {
+          return nsi.isGenericName(tags);
+        }
+      }
+      return false;
     }
-    for (var tag in patterns) {
-      var entityValue = tags[tag];
-      if (!entityValue)
-        continue;
-      if (typeof patterns[tag] === "string") {
-        return "pattern-" + patterns[tag];
-      } else {
-        var values = patterns[tag];
-        for (var value in values) {
-          if (entityValue !== value)
-            continue;
-          var rules = values[value];
-          if (typeof rules === "string") {
-            return "pattern-" + rules;
-          }
-          for (var ruleKey in rules) {
-            var rule = rules[ruleKey];
-            var pass = true;
-            for (var criterion in rule) {
-              if (criterion !== "pattern") {
-                var v = tags[criterion];
-                if (!v || v !== rule[criterion]) {
-                  pass = false;
-                  break;
-                }
-              }
-            }
-            if (pass) {
-              return "pattern-" + rule.pattern;
-            }
+    function nameMatchesRawTag(lowercaseName, tags) {
+      for (let i3 = 0; i3 < keysToTestForGenericValues.length; i3++) {
+        let key = keysToTestForGenericValues[i3];
+        let val = tags[key];
+        if (val) {
+          val = val.toLowerCase();
+          if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, " ") === lowercaseName || val.replace(/\_/g, " ") === lowercaseName) {
+            return true;
           }
         }
       }
+      return false;
     }
-    return null;
-  }
-
-  // modules/svg/areas.js
-  function svgAreas(projection2, context) {
-    function getPatternStyle(tags) {
-      var imageID = svgTagPattern(tags);
-      if (imageID) {
-        return 'url("#ideditor-' + imageID + '")';
-      }
-      return "";
+    function isGenericName(name, tags) {
+      name = name.toLowerCase();
+      return nameMatchesRawTag(name, tags) || isGenericMatchInNsi(tags);
     }
-    function drawTargets(selection2, graph, entities, filter2) {
-      var targetClass = context.getDebug("target") ? "pink " : "nocolor ";
-      var nopeClass = context.getDebug("target") ? "red " : "nocolor ";
-      var getPath = svgPath(projection2).geojson;
-      var activeID = context.activeID();
-      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 targetData = data.targets.filter(getPath);
-      var targets = selection2.selectAll(".area.target-allowed").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(targetData, function key(d) {
-        return d.id;
-      });
-      targets.exit().remove();
-      var segmentWasEdited = function(d) {
-        var wayID = d.properties.entity.id;
-        if (!base.entities[wayID] || !(0, import_fast_deep_equal5.default)(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
-          return false;
+    function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
+      return new validationIssue({
+        type: type2,
+        subtype: "generic_name",
+        severity: "warning",
+        message: function(context) {
+          let entity = context.hasEntity(this.entityIds[0]);
+          if (!entity) return "";
+          let preset = _mainPresetIndex.match(entity, context.graph());
+          let langName = langCode && _mainLocalizer.languageName(langCode);
+          return _t.append(
+            "issues.generic_name.message" + (langName ? "_language" : ""),
+            { feature: preset.name(), name: genericName, language: langName }
+          );
+        },
+        reference: showReference,
+        entityIds: [entityId],
+        hash: "".concat(nameKey, "=").concat(genericName),
+        dynamicFixes: function() {
+          return [
+            new validationIssueFix({
+              icon: "iD-operation-delete",
+              title: _t.append("issues.fix.remove_the_name.title"),
+              onClick: function(context) {
+                let entityId2 = this.issue.entityIds[0];
+                let entity = context.entity(entityId2);
+                let tags = Object.assign({}, entity.tags);
+                delete tags[nameKey];
+                context.perform(
+                  actionChangeTags(entityId2, tags),
+                  _t("issues.fix.remove_generic_name.annotation")
+                );
+              }
+            })
+          ];
         }
-        return d.properties.nodes.some(function(n2) {
-          return !base.entities[n2.id] || !(0, import_fast_deep_equal5.default)(graph.entities[n2.id].loc, base.entities[n2.id].loc);
-        });
-      };
-      targets.enter().append("path").merge(targets).attr("d", getPath).attr("class", function(d) {
-        return "way area target target-allowed " + targetClass + d.id;
-      }).classed("segment-edited", segmentWasEdited);
-      var nopeData = data.nopes.filter(getPath);
-      var nopes = selection2.selectAll(".area.target-nope").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(nopeData, function key(d) {
-        return d.id;
       });
-      nopes.exit().remove();
-      nopes.enter().append("path").merge(nopes).attr("d", getPath).attr("class", function(d) {
-        return "way area target target-nope " + nopeClass + d.id;
-      }).classed("segment-edited", segmentWasEdited);
-    }
-    function drawAreas(selection2, graph, entities, filter2) {
-      var path = svgPath(projection2, graph, true);
-      var areas = {};
-      var multipolygon;
-      var base = context.history().base();
-      for (var i2 = 0; i2 < entities.length; i2++) {
-        var entity = entities[i2];
-        if (entity.geometry(graph) !== "area")
-          continue;
-        multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
-        if (multipolygon) {
-          areas[multipolygon.id] = {
-            entity: multipolygon.mergeTags(entity.tags),
-            area: Math.abs(entity.area(graph))
-          };
-        } else if (!areas[entity.id]) {
-          areas[entity.id] = {
-            entity,
-            area: Math.abs(entity.area(graph))
-          };
-        }
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.generic_name.reference"));
       }
-      var fills = Object.values(areas).filter(function hasPath(a) {
-        return path(a.entity);
-      });
-      fills.sort(function areaSort(a, b) {
-        return b.area - a.area;
-      });
-      fills = fills.map(function(a) {
-        return a.entity;
-      });
-      var strokes = fills.filter(function(area) {
-        return area.type === "way";
-      });
-      var data = {
-        clip: fills,
-        shadow: strokes,
-        stroke: strokes,
-        fill: fills
-      };
-      var clipPaths = context.surface().selectAll("defs").selectAll(".clipPath-osm").filter(filter2).data(data.clip, osmEntity.key);
-      clipPaths.exit().remove();
-      var clipPathsEnter = clipPaths.enter().append("clipPath").attr("class", "clipPath-osm").attr("id", function(entity2) {
-        return "ideditor-" + entity2.id + "-clippath";
-      });
-      clipPathsEnter.append("path");
-      clipPaths.merge(clipPathsEnter).selectAll("path").attr("d", path);
-      var drawLayer = selection2.selectAll(".layer-osm.areas");
-      var touchLayer = selection2.selectAll(".layer-touch.areas");
-      var areagroup = drawLayer.selectAll("g.areagroup").data(["fill", "shadow", "stroke"]);
-      areagroup = areagroup.enter().append("g").attr("class", function(d) {
-        return "areagroup area-" + d;
-      }).merge(areagroup);
-      var paths = areagroup.selectAll("path").filter(filter2).data(function(layer) {
-        return data[layer];
-      }, osmEntity.key);
-      paths.exit().remove();
-      var fillpaths = selection2.selectAll(".area-fill path.area").nodes();
-      var bisect = bisector(function(node) {
-        return -node.__data__.area(graph);
-      }).left;
-      function sortedByArea(entity2) {
-        if (this._parent.__data__ === "fill") {
-          return fillpaths[bisect(fillpaths, -entity2.area(graph))];
+    }
+    let validation = function checkGenericName(entity) {
+      const tags = entity.tags;
+      const hasWikidata = !!tags.wikidata || !!tags["brand:wikidata"] || !!tags["operator:wikidata"];
+      if (hasWikidata) return [];
+      let issues = [];
+      for (let key in tags) {
+        const m2 = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
+        if (!m2) continue;
+        const langCode = m2.length >= 2 ? m2[1] : null;
+        const value = tags[key];
+        if (isGenericName(value, tags)) {
+          issues.provisional = _waitingForNsi;
+          issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
         }
       }
-      paths = paths.enter().insert("path", sortedByArea).merge(paths).each(function(entity2) {
-        var layer = this.parentNode.__data__;
-        this.setAttribute("class", entity2.type + " area " + layer + " " + entity2.id);
-        if (layer === "fill") {
-          this.setAttribute("clip-path", "url(#ideditor-" + entity2.id + "-clippath)");
-          this.style.fill = this.style.stroke = getPatternStyle(entity2.tags);
-        }
-      }).classed("added", function(d) {
-        return !base.entities[d.id];
-      }).classed("geometry-edited", function(d) {
-        return graph.entities[d.id] && base.entities[d.id] && !(0, import_fast_deep_equal5.default)(graph.entities[d.id].nodes, base.entities[d.id].nodes);
-      }).classed("retagged", function(d) {
-        return graph.entities[d.id] && base.entities[d.id] && !(0, import_fast_deep_equal5.default)(graph.entities[d.id].tags, base.entities[d.id].tags);
-      }).call(svgTagClasses()).attr("d", path);
-      touchLayer.call(drawTargets, graph, data.stroke, filter2);
-    }
-    return drawAreas;
+      return issues;
+    };
+    validation.type = type2;
+    return validation;
   }
 
-  // modules/svg/data.js
-  var import_fast_json_stable_stringify = __toESM(require_fast_json_stable_stringify());
-
-  // node_modules/@tmcw/togeojson/dist/togeojson.es.mjs
-  function $(element, tagName) {
-    return Array.from(element.getElementsByTagName(tagName));
-  }
-  function normalizeId(id2) {
-    return id2[0] === "#" ? id2 : `#${id2}`;
-  }
-  function $ns(element, tagName, ns) {
-    return Array.from(element.getElementsByTagNameNS(ns, tagName));
-  }
-  function nodeVal(node) {
-    node?.normalize();
-    return node && node.textContent || "";
-  }
-  function get1(node, tagName, callback) {
-    const n2 = node.getElementsByTagName(tagName);
-    const result = n2.length ? n2[0] : null;
-    if (result && callback)
-      callback(result);
-    return result;
-  }
-  function get3(node, tagName, callback) {
-    const properties = {};
-    if (!node)
-      return properties;
-    const n2 = node.getElementsByTagName(tagName);
-    const result = n2.length ? n2[0] : null;
-    if (result && callback) {
-      return callback(result, properties);
+  // modules/validations/unsquare_way.js
+  function validationUnsquareWay(context) {
+    var type2 = "unsquare_way";
+    var DEFAULT_DEG_THRESHOLD = 5;
+    var epsilon3 = 0.05;
+    var nodeThreshold = 10;
+    function isBuilding(entity, graph) {
+      if (entity.type !== "way" || entity.geometry(graph) !== "area") return false;
+      return entity.tags.building && entity.tags.building !== "no";
     }
-    return properties;
-  }
-  function val1(node, tagName, callback) {
-    const val = nodeVal(get1(node, tagName));
-    if (val && callback)
-      return callback(val) || {};
-    return {};
-  }
-  function $num(node, tagName, callback) {
-    const val = parseFloat(nodeVal(get1(node, tagName)));
-    if (isNaN(val))
-      return void 0;
-    if (val && callback)
-      return callback(val) || {};
-    return {};
-  }
-  function num1(node, tagName, callback) {
-    const val = parseFloat(nodeVal(get1(node, tagName)));
-    if (isNaN(val))
-      return void 0;
-    if (val && callback)
-      callback(val);
-    return val;
-  }
-  function getMulti(node, propertyNames) {
-    const properties = {};
-    for (const property of propertyNames) {
-      val1(node, property, (val) => {
-        properties[property] = val;
+    var validation = function checkUnsquareWay(entity, graph) {
+      if (!isBuilding(entity, graph)) return [];
+      if (entity.tags.nonsquare === "yes") return [];
+      var isClosed = entity.isClosed();
+      if (!isClosed) return [];
+      var nodes = graph.childNodes(entity).slice();
+      if (nodes.length > nodeThreshold + 1) return [];
+      var osm = services.osm;
+      if (!osm || nodes.some(function(node) {
+        return !osm.isDataLoaded(node.loc);
+      })) return [];
+      var hasConnectedSquarableWays = nodes.some(function(node) {
+        return graph.parentWays(node).some(function(way) {
+          if (way.id === entity.id) return false;
+          if (isBuilding(way, graph)) return true;
+          return graph.parentRelations(way).some(function(parentRelation) {
+            return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== "no";
+          });
+        });
       });
-    }
-    return properties;
-  }
-  function isElement(node) {
-    return node?.nodeType === 1;
-  }
-  function getLineStyle(node) {
-    return get3(node, "line", (lineStyle) => {
-      const val = Object.assign({}, val1(lineStyle, "color", (color2) => {
-        return { stroke: `#${color2}` };
-      }), $num(lineStyle, "opacity", (opacity) => {
-        return { "stroke-opacity": opacity };
-      }), $num(lineStyle, "width", (width) => {
-        return { "stroke-width": width * 96 / 25.4 };
-      }));
-      return val;
-    });
-  }
-  function getExtensions(node) {
-    let values = [];
-    if (node === null)
-      return values;
-    for (const child of Array.from(node.childNodes)) {
-      if (!isElement(child))
-        continue;
-      const name = abbreviateName(child.nodeName);
-      if (name === "gpxtpx:TrackPointExtension") {
-        values = values.concat(getExtensions(child));
-      } else {
-        const val = nodeVal(child);
-        values.push([name, parseNumeric(val)]);
+      if (hasConnectedSquarableWays) return [];
+      var storedDegreeThreshold = corePreferences("validate-square-degrees");
+      var degreeThreshold = isFinite(storedDegreeThreshold) ? Number(storedDegreeThreshold) : DEFAULT_DEG_THRESHOLD;
+      var points = nodes.map(function(node) {
+        return context.projection(node.loc);
+      });
+      if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon3, degreeThreshold, true)) return [];
+      var autoArgs;
+      if (!entity.tags.wikidata) {
+        var autoAction = actionOrthogonalize(entity.id, context.projection, void 0, degreeThreshold);
+        autoAction.transitionable = false;
+        autoArgs = [autoAction, _t("operations.orthogonalize.annotation.feature", { n: 1 })];
+      }
+      return [new validationIssue({
+        type: type2,
+        subtype: "building",
+        severity: "warning",
+        message: function(context2) {
+          var entity2 = context2.hasEntity(this.entityIds[0]);
+          return entity2 ? _t.append("issues.unsquare_way.message", {
+            feature: utilDisplayLabel(entity2, context2.graph())
+          }) : "";
+        },
+        reference: showReference,
+        entityIds: [entity.id],
+        hash: degreeThreshold,
+        dynamicFixes: function() {
+          return [
+            new validationIssueFix({
+              icon: "iD-operation-orthogonalize",
+              title: _t.append("issues.fix.square_feature.title"),
+              autoArgs,
+              onClick: function(context2, completionHandler) {
+                var entityId = this.issue.entityIds[0];
+                context2.perform(
+                  actionOrthogonalize(entityId, context2.projection, void 0, degreeThreshold),
+                  _t("operations.orthogonalize.annotation.feature", { n: 1 })
+                );
+                window.setTimeout(function() {
+                  completionHandler();
+                }, 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')
+                    );
+                }
+            })
+            */
+          ];
+        }
+      })];
+      function showReference(selection2) {
+        selection2.selectAll(".issue-reference").data([0]).enter().append("div").attr("class", "issue-reference").call(_t.append("issues.unsquare_way.buildings.reference"));
       }
-    }
-    return values;
-  }
-  function abbreviateName(name) {
-    return ["heart", "gpxtpx:hr", "hr"].includes(name) ? "heart" : name;
-  }
-  function parseNumeric(val) {
-    const num = parseFloat(val);
-    return isNaN(num) ? val : num;
-  }
-  function coordPair$1(node) {
-    const ll = [
-      parseFloat(node.getAttribute("lon") || ""),
-      parseFloat(node.getAttribute("lat") || "")
-    ];
-    if (isNaN(ll[0]) || isNaN(ll[1])) {
-      return null;
-    }
-    num1(node, "ele", (val) => {
-      ll.push(val);
-    });
-    const time = get1(node, "time");
-    return {
-      coordinates: ll,
-      time: time ? nodeVal(time) : null,
-      extendedValues: getExtensions(get1(node, "extensions"))
     };
+    validation.type = type2;
+    return validation;
   }
-  function extractProperties(node) {
-    const properties = getMulti(node, [
-      "name",
-      "cmt",
-      "desc",
-      "type",
-      "time",
-      "keywords"
-    ]);
-    const extensions = Array.from(node.getElementsByTagNameNS("http://www.garmin.com/xmlschemas/GpxExtensions/v3", "*"));
-    for (const child of extensions) {
-      if (child.parentNode?.parentNode === node) {
-        properties[child.tagName.replace(":", "_")] = nodeVal(child);
+
+  // modules/core/validator.js
+  function coreValidator(context) {
+    let dispatch14 = dispatch_default("validated", "focusedIssue");
+    let validator = utilRebind({}, dispatch14, "on");
+    let _rules = {};
+    let _disabledRules = {};
+    let _ignoredIssueIDs = /* @__PURE__ */ new Set();
+    let _resolvedIssueIDs = /* @__PURE__ */ new Set();
+    let _baseCache = validationCache("base");
+    let _headCache = validationCache("head");
+    let _completeDiff = {};
+    let _headIsCurrent = false;
+    let _deferredRIC = {};
+    let _deferredST = /* @__PURE__ */ new Set();
+    let _headPromise;
+    const RETRY = 5e3;
+    const _errorOverrides = parseHashParam(context.initialHashParams.validationError);
+    const _warningOverrides = parseHashParam(context.initialHashParams.validationWarning);
+    const _disableOverrides = parseHashParam(context.initialHashParams.validationDisable);
+    function parseHashParam(param) {
+      let result = [];
+      let rules = (param || "").split(",");
+      rules.forEach((rule) => {
+        rule = rule.trim();
+        const parts = rule.split("/", 2);
+        const type2 = parts[0];
+        const subtype = parts[1] || "*";
+        if (!type2 || !subtype) return;
+        result.push({ type: makeRegExp(type2), subtype: makeRegExp(subtype) });
+      });
+      return result;
+      function makeRegExp(str) {
+        const escaped = str.replace(/[-\/\\^$+?.()|[\]{}]/g, "\\$&").replace(/\*/g, ".*");
+        return new RegExp("^" + escaped + "$");
       }
     }
-    const links = $(node, "link");
-    if (links.length) {
-      properties.links = links.map((link2) => Object.assign({ href: link2.getAttribute("href") }, getMulti(link2, ["text", "type"])));
-    }
-    return properties;
-  }
-  function getPoints$1(node, pointname) {
-    const pts = $(node, pointname);
-    const line = [];
-    const times = [];
-    const extendedValues = {};
-    for (let i2 = 0; i2 < pts.length; i2++) {
-      const c = coordPair$1(pts[i2]);
-      if (!c) {
-        continue;
-      }
-      line.push(c.coordinates);
-      if (c.time)
-        times.push(c.time);
-      for (const [name, val] of c.extendedValues) {
-        const plural = name === "heart" ? name : name.replace("gpxtpx:", "") + "s";
-        if (!extendedValues[plural]) {
-          extendedValues[plural] = Array(pts.length).fill(null);
-        }
-        extendedValues[plural][i2] = val;
+    validator.init = () => {
+      Object.values(validations_exports).forEach((validation) => {
+        if (typeof validation !== "function") return;
+        const fn = validation(context);
+        const key = fn.type;
+        _rules[key] = fn;
+      });
+      let disabledRules = corePreferences("validate-disabledRules");
+      if (disabledRules) {
+        disabledRules.split(",").forEach((k2) => _disabledRules[k2] = true);
       }
+    };
+    function reset(resetIgnored) {
+      _baseCache.queue = [];
+      _headCache.queue = [];
+      Object.keys(_deferredRIC).forEach((key) => {
+        window.cancelIdleCallback(key);
+        _deferredRIC[key]();
+      });
+      _deferredRIC = {};
+      _deferredST.forEach(window.clearTimeout);
+      _deferredST.clear();
+      if (resetIgnored) _ignoredIssueIDs.clear();
+      _resolvedIssueIDs.clear();
+      _baseCache = validationCache("base");
+      _headCache = validationCache("head");
+      _completeDiff = {};
+      _headIsCurrent = false;
     }
-    if (line.length < 2)
-      return;
-    return {
-      line,
-      times,
-      extendedValues
+    validator.reset = () => {
+      reset(true);
     };
-  }
-  function getRoute(node) {
-    const line = getPoints$1(node, "rtept");
-    if (!line)
-      return;
-    return {
-      type: "Feature",
-      properties: Object.assign({ _gpxType: "rte" }, extractProperties(node), getLineStyle(get1(node, "extensions"))),
-      geometry: {
-        type: "LineString",
-        coordinates: line.line
-      }
+    validator.resetIgnoredIssues = () => {
+      _ignoredIssueIDs.clear();
+      dispatch14.call("validated");
     };
-  }
-  function getTrack(node) {
-    const segments = $(node, "trkseg");
-    const track = [];
-    const times = [];
-    const extractedLines = [];
-    for (const segment of segments) {
-      const line = getPoints$1(segment, "trkpt");
-      if (line) {
-        extractedLines.push(line);
-        if (line.times && line.times.length)
-          times.push(line.times);
-      }
+    validator.revalidateUnsquare = () => {
+      revalidateUnsquare(_headCache);
+      revalidateUnsquare(_baseCache);
+      dispatch14.call("validated");
+    };
+    function revalidateUnsquare(cache) {
+      const checkUnsquareWay = _rules.unsquare_way;
+      if (!cache.graph || typeof checkUnsquareWay !== "function") return;
+      cache.uncacheIssuesOfType("unsquare_way");
+      const buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), cache.graph).filter((entity) => entity.type === "way" && entity.tags.building && entity.tags.building !== "no");
+      buildings.forEach((entity) => {
+        const detected = checkUnsquareWay(entity, cache.graph);
+        if (!detected.length) return;
+        cache.cacheIssues(detected);
+      });
     }
-    if (extractedLines.length === 0)
-      return null;
-    const multi = extractedLines.length > 1;
-    const properties = Object.assign({ _gpxType: "trk" }, extractProperties(node), getLineStyle(get1(node, "extensions")), times.length ? {
-      coordinateProperties: {
-        times: multi ? times : times[0]
+    validator.getIssues = (options2) => {
+      const opts = Object.assign({ what: "all", where: "all", includeIgnored: false, includeDisabledRules: false }, options2);
+      const view = context.map().extent();
+      let seen = /* @__PURE__ */ new Set();
+      let results = [];
+      if (_headCache.graph && _headCache.graph !== _baseCache.graph) {
+        Object.values(_headCache.issuesByIssueID).forEach((issue) => {
+          const userModified = (issue.entityIds || []).some((id2) => _completeDiff.hasOwnProperty(id2));
+          if (opts.what === "edited" && !userModified) return;
+          if (!filter2(issue)) return;
+          seen.add(issue.id);
+          results.push(issue);
+        });
       }
-    } : {});
-    for (const line of extractedLines) {
-      track.push(line.line);
-      if (!properties.coordinateProperties) {
-        properties.coordinateProperties = {};
+      if (opts.what === "all") {
+        Object.values(_baseCache.issuesByIssueID).forEach((issue) => {
+          if (!filter2(issue)) return;
+          seen.add(issue.id);
+          results.push(issue);
+        });
       }
-      const props = properties.coordinateProperties;
-      const entries = Object.entries(line.extendedValues);
-      for (let i2 = 0; i2 < entries.length; i2++) {
-        const [name, val] = entries[i2];
-        if (multi) {
-          if (!props[name]) {
-            props[name] = extractedLines.map((line2) => new Array(line2.line.length).fill(null));
+      return results;
+      function filter2(issue) {
+        if (!issue) return false;
+        if (seen.has(issue.id)) return false;
+        if (_resolvedIssueIDs.has(issue.id)) return false;
+        if (opts.includeDisabledRules === "only" && !_disabledRules[issue.type]) return false;
+        if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
+        if (opts.includeIgnored === "only" && !_ignoredIssueIDs.has(issue.id)) return false;
+        if (!opts.includeIgnored && _ignoredIssueIDs.has(issue.id)) return false;
+        if ((issue.entityIds || []).some((id2) => !context.hasEntity(id2))) return false;
+        if (opts.where === "visible") {
+          const extent = issue.extent(context.graph());
+          if (!view.intersects(extent)) return false;
+        }
+        return true;
+      }
+    };
+    validator.getResolvedIssues = () => {
+      return Array.from(_resolvedIssueIDs).map((issueID) => _baseCache.issuesByIssueID[issueID]).filter(Boolean);
+    };
+    validator.focusIssue = (issue) => {
+      const graph = context.graph();
+      let selectID;
+      let focusCenter;
+      const issueExtent = issue.extent(graph);
+      if (issueExtent) {
+        focusCenter = issueExtent.center();
+      }
+      if (issue.entityIds && issue.entityIds.length) {
+        selectID = issue.entityIds[0];
+        if (selectID && selectID.charAt(0) === "r") {
+          const ids = utilEntityAndDeepMemberIDs([selectID], graph);
+          let nodeID = ids.find((id2) => id2.charAt(0) === "n" && graph.hasEntity(id2));
+          if (!nodeID) {
+            const wayID = ids.find((id2) => id2.charAt(0) === "w" && graph.hasEntity(id2));
+            if (wayID) {
+              nodeID = graph.entity(wayID).first();
+            }
+          }
+          if (nodeID) {
+            focusCenter = graph.entity(nodeID).loc;
           }
-          props[name][i2] = val;
-        } else {
-          props[name] = val;
         }
       }
-    }
-    return {
-      type: "Feature",
-      properties,
-      geometry: multi ? {
-        type: "MultiLineString",
-        coordinates: track
-      } : {
-        type: "LineString",
-        coordinates: track[0]
+      if (focusCenter) {
+        const setZoom = Math.max(context.map().zoom(), 19);
+        context.map().unobscuredCenterZoomEase(focusCenter, setZoom);
+      }
+      if (selectID) {
+        window.setTimeout(() => {
+          context.enter(modeSelect(context, [selectID]));
+          dispatch14.call("focusedIssue", this, issue);
+        }, 250);
       }
     };
-  }
-  function getPoint(node) {
-    const properties = Object.assign(extractProperties(node), getMulti(node, ["sym"]));
-    const pair2 = coordPair$1(node);
-    if (!pair2)
-      return null;
-    return {
-      type: "Feature",
-      properties,
-      geometry: {
-        type: "Point",
-        coordinates: pair2.coordinates
+    validator.getIssuesBySeverity = (options2) => {
+      let groups = utilArrayGroupBy(validator.getIssues(options2), "severity");
+      groups.error = groups.error || [];
+      groups.warning = groups.warning || [];
+      return groups;
+    };
+    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);
+      return allIssues.filter((issue) => (issue.entityIds || []).some((entityID) => forEntityIDs.has(entityID))).sort((issue1, issue2) => {
+        if (issue1.type === issue2.type) {
+          return issue1.id < issue2.id ? -1 : 1;
+        }
+        const index1 = orderedIssueTypes.indexOf(issue1.type);
+        const index2 = orderedIssueTypes.indexOf(issue2.type);
+        if (index1 !== -1 && index2 !== -1) {
+          return index1 - index2;
+        } else if (index1 === -1 && index2 === -1) {
+          return issue1.type < issue2.type ? -1 : 1;
+        } else {
+          return index1 !== -1 ? -1 : 1;
+        }
+      });
+    };
+    validator.getEntityIssues = (entityID, options2) => {
+      return validator.getSharedEntityIssues([entityID], options2);
+    };
+    validator.getRuleKeys = () => {
+      return Object.keys(_rules);
+    };
+    validator.isRuleEnabled = (key) => {
+      return !_disabledRules[key];
+    };
+    validator.toggleRule = (key) => {
+      if (_disabledRules[key]) {
+        delete _disabledRules[key];
+      } else {
+        _disabledRules[key] = true;
       }
+      corePreferences("validate-disabledRules", Object.keys(_disabledRules).join(","));
+      validator.validate();
     };
-  }
-  function* gpxGen(node) {
-    for (const track of $(node, "trk")) {
-      const feature3 = getTrack(track);
-      if (feature3)
-        yield feature3;
-    }
-    for (const route of $(node, "rte")) {
-      const feature3 = getRoute(route);
-      if (feature3)
-        yield feature3;
-    }
-    for (const waypoint of $(node, "wpt")) {
-      const point = getPoint(waypoint);
-      if (point)
-        yield point;
-    }
-  }
-  function gpx(node) {
-    return {
-      type: "FeatureCollection",
-      features: Array.from(gpxGen(node))
+    validator.disableRules = (keys2) => {
+      _disabledRules = {};
+      keys2.forEach((k2) => _disabledRules[k2] = true);
+      corePreferences("validate-disabledRules", Object.keys(_disabledRules).join(","));
+      validator.validate();
     };
-  }
-  function fixColor(v, prefix) {
-    const properties = {};
-    const colorProp = prefix == "stroke" || prefix === "fill" ? prefix : prefix + "-color";
-    if (v[0] === "#") {
-      v = v.substring(1);
-    }
-    if (v.length === 6 || v.length === 3) {
-      properties[colorProp] = "#" + v;
-    } else if (v.length === 8) {
-      properties[prefix + "-opacity"] = parseInt(v.substring(0, 2), 16) / 255;
-      properties[colorProp] = "#" + v.substring(6, 8) + v.substring(4, 6) + v.substring(2, 4);
-    }
-    return properties;
-  }
-  function numericProperty(node, source, target) {
-    const properties = {};
-    num1(node, source, (val) => {
-      properties[target] = val;
-    });
-    return properties;
-  }
-  function getColor(node, output) {
-    return get3(node, "color", (elem) => fixColor(nodeVal(elem), output));
-  }
-  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) => {
-        const left = parseFloat(hotspot.getAttribute("x") || "");
-        const top = parseFloat(hotspot.getAttribute("y") || "");
-        const xunits = hotspot.getAttribute("xunits") || "";
-        const yunits = hotspot.getAttribute("yunits") || "";
-        if (!isNaN(left) && !isNaN(top))
-          return {
-            "icon-offset": [left, top],
-            "icon-offset-units": [xunits, yunits]
-          };
-        return {};
-      }), get3(iconStyle, "Icon", (icon2, properties) => {
-        val1(icon2, "href", (href) => {
-          properties.icon = href;
-        });
-        return properties;
-      }));
+    validator.ignoreIssue = (issueID) => {
+      _ignoredIssueIDs.add(issueID);
+    };
+    validator.validate = () => {
+      const baseGraph = context.history().base();
+      if (!_headCache.graph) _headCache.graph = baseGraph;
+      if (!_baseCache.graph) _baseCache.graph = baseGraph;
+      const prevGraph = _headCache.graph;
+      const currGraph = context.graph();
+      if (currGraph === prevGraph) {
+        _headIsCurrent = true;
+        dispatch14.call("validated");
+        return Promise.resolve();
+      }
+      if (_headPromise) {
+        _headIsCurrent = false;
+        return _headPromise;
+      }
+      _headCache.graph = currGraph;
+      _completeDiff = context.history().difference().complete();
+      const incrementalDiff = coreDifference(prevGraph, currGraph);
+      let entityIDs = Object.keys(incrementalDiff.complete());
+      entityIDs = _headCache.withAllRelatedEntities(entityIDs);
+      if (!entityIDs.size) {
+        dispatch14.call("validated");
+        return Promise.resolve();
+      }
+      _headPromise = validateEntitiesAsync(entityIDs, _headCache).then(() => updateResolvedIssues(entityIDs)).then(() => dispatch14.call("validated")).catch(() => {
+      }).then(() => {
+        _headPromise = null;
+        if (!_headIsCurrent) {
+          validator.validate();
+        }
+      });
+      return _headPromise;
+    };
+    context.history().on("restore.validator", validator.validate).on("undone.validator", validator.validate).on("redone.validator", validator.validate).on("reset.validator", () => {
+      reset(false);
+      validator.validate();
     });
-  }
-  function extractLabel(node) {
-    return get3(node, "LabelStyle", (labelStyle) => {
-      return Object.assign(getColor(labelStyle, "label"), numericProperty(labelStyle, "scale", "label-scale"));
+    context.on("exit.validator", validator.validate);
+    context.history().on("merge.validator", (entities) => {
+      if (!entities) return;
+      const baseGraph = context.history().base();
+      if (!_headCache.graph) _headCache.graph = baseGraph;
+      if (!_baseCache.graph) _baseCache.graph = baseGraph;
+      let entityIDs = entities.map((entity) => entity.id);
+      entityIDs = _baseCache.withAllRelatedEntities(entityIDs);
+      validateEntitiesAsync(entityIDs, _baseCache);
     });
-  }
-  function extractLine(node) {
-    return get3(node, "LineStyle", (lineStyle) => {
-      return Object.assign(getColor(lineStyle, "stroke"), numericProperty(lineStyle, "width", "stroke-width"));
-    });
-  }
-  function extractPoly(node) {
-    return get3(node, "PolyStyle", (polyStyle, properties) => {
-      return Object.assign(properties, get3(polyStyle, "color", (elem) => fixColor(nodeVal(elem), "fill")), val1(polyStyle, "fill", (fill) => {
-        if (fill === "0")
-          return { "fill-opacity": 0 };
-      }), val1(polyStyle, "outline", (outline) => {
-        if (outline === "0")
-          return { "stroke-opacity": 0 };
-      }));
-    });
-  }
-  function extractStyle(node) {
-    return Object.assign({}, extractPoly(node), extractLine(node), extractLabel(node), extractIcon(node));
-  }
-  var removeSpace = /\s*/g;
-  var trimSpace = /^\s*|\s*$/g;
-  var splitSpace = /\s+/;
-  function coord1(value) {
-    return value.replace(removeSpace, "").split(",").map(parseFloat).filter((num) => !isNaN(num)).slice(0, 3);
-  }
-  function coord(value) {
-    return value.replace(trimSpace, "").split(splitSpace).map(coord1).filter((coord2) => {
-      return coord2.length >= 2;
-    });
-  }
-  function gxCoords(node) {
-    let elems = $(node, "coord");
-    if (elems.length === 0) {
-      elems = $ns(node, "coord", "*");
-    }
-    const coordinates = elems.map((elem) => {
-      return nodeVal(elem).split(" ").map(parseFloat);
-    });
-    if (coordinates.length === 0) {
-      return null;
-    }
-    return {
-      geometry: coordinates.length > 2 ? {
-        type: "LineString",
-        coordinates
-      } : {
-        type: "Point",
-        coordinates: coordinates[0]
-      },
-      times: $(node, "when").map((elem) => nodeVal(elem))
-    };
-  }
-  function fixRing(ring) {
-    if (ring.length === 0)
-      return ring;
-    const first = ring[0];
-    const last = ring[ring.length - 1];
-    let equal = true;
-    for (let i2 = 0; i2 < Math.max(first.length, last.length); i2++) {
-      if (first[i2] !== last[i2]) {
-        equal = false;
-        break;
-      }
-    }
-    if (!equal) {
-      return ring.concat([ring[0]]);
-    }
-    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) {
-          case "Point": {
-            const coordinates = coord1(getCoordinates(geomNode));
-            if (coordinates.length >= 2) {
-              geometries.push({
-                type: "Point",
-                coordinates
-              });
+    function validateEntity(entity, graph) {
+      let result = { issues: [], provisional: false };
+      Object.keys(_rules).forEach(runValidation);
+      return result;
+      function runValidation(key) {
+        const fn = _rules[key];
+        if (typeof fn !== "function") {
+          console.error("no such validation rule = " + key);
+          return;
+        }
+        let detected = fn(entity, graph);
+        if (detected.provisional) {
+          result.provisional = true;
+        }
+        detected = detected.filter(applySeverityOverrides);
+        result.issues = result.issues.concat(detected);
+        function applySeverityOverrides(issue) {
+          const type2 = issue.type;
+          const subtype = issue.subtype || "";
+          let i3;
+          for (i3 = 0; i3 < _errorOverrides.length; i3++) {
+            if (_errorOverrides[i3].type.test(type2) && _errorOverrides[i3].subtype.test(subtype)) {
+              issue.severity = "error";
+              return true;
             }
-            break;
           }
-          case "LineString": {
-            const coordinates = coord(getCoordinates(geomNode));
-            if (coordinates.length >= 2) {
-              geometries.push({
-                type: "LineString",
-                coordinates
-              });
+          for (i3 = 0; i3 < _warningOverrides.length; i3++) {
+            if (_warningOverrides[i3].type.test(type2) && _warningOverrides[i3].subtype.test(subtype)) {
+              issue.severity = "warning";
+              return true;
             }
-            break;
           }
-          case "Polygon": {
-            const coords = [];
-            for (const linearRing of $(geomNode, "LinearRing")) {
-              const ring = fixRing(coord(getCoordinates(linearRing)));
-              if (ring.length >= 4) {
-                coords.push(ring);
-              }
-            }
-            if (coords.length) {
-              geometries.push({
-                type: "Polygon",
-                coordinates: coords
-              });
+          for (i3 = 0; i3 < _disableOverrides.length; i3++) {
+            if (_disableOverrides[i3].type.test(type2) && _disableOverrides[i3].subtype.test(subtype)) {
+              return false;
             }
-            break;
-          }
-          case "Track":
-          case "gx:Track": {
-            const gx = gxCoords(geomNode);
-            if (!gx)
-              break;
-            const { times, geometry } = gx;
-            geometries.push(geometry);
-            if (times.length)
-              coordTimes.push(times);
-            break;
           }
+          return true;
         }
       }
     }
-    return {
-      geometries,
-      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)
+    function updateResolvedIssues(entityIDs) {
+      entityIDs.forEach((entityID) => {
+        const baseIssues = _baseCache.issuesByEntityID[entityID];
+        if (!baseIssues) return;
+        baseIssues.forEach((issueID) => {
+          const issue = _baseCache.issuesByIssueID[issueID];
+          const userModified = (issue.entityIds || []).some((id2) => _completeDiff.hasOwnProperty(id2));
+          if (userModified && !_headCache.issuesByIssueID[issueID]) {
+            _resolvedIssueIDs.add(issueID);
+          } else {
+            _resolvedIssueIDs.delete(issueID);
+          }
+        });
+      });
+    }
+    function validateEntitiesAsync(entityIDs, cache) {
+      const jobs = Array.from(entityIDs).map((entityID) => {
+        if (cache.queuedEntityIDs.has(entityID)) return null;
+        cache.queuedEntityIDs.add(entityID);
+        cache.uncacheEntityID(entityID);
+        return () => {
+          cache.queuedEntityIDs.delete(entityID);
+          const graph = cache.graph;
+          if (!graph) return;
+          const entity = graph.hasEntity(entityID);
+          if (!entity) return;
+          const result = validateEntity(entity, graph);
+          if (result.provisional) {
+            cache.provisionalEntityIDs.add(entityID);
           }
+          cache.cacheIssues(result.issues);
         };
-      }
+      }).filter(Boolean);
+      cache.queue = cache.queue.concat(utilArrayChunk(jobs, 100));
+      if (cache.queuePromise) return cache.queuePromise;
+      cache.queuePromise = processQueue(cache).then(() => revalidateProvisionalEntities(cache)).catch(() => {
+      }).finally(() => cache.queuePromise = null);
+      return cache.queuePromise;
     }
-    return {};
-  }
-  function getPlacemark(node, styleMap) {
-    const { coordTimes, geometries } = getGeometry(node);
-    const feature3 = {
-      type: "Feature",
-      geometry: geometryListToGeometry(geometries),
-      properties: Object.assign(getMulti(node, [
-        "name",
-        "address",
-        "visibility",
-        "open",
-        "phoneNumber",
-        "description"
-      ]), getMaybeHTMLDescription(node), extractCascadedStyle(node, styleMap), extractStyle(node), extractExtendedData(node), extractTimeSpan(node), extractTimeStamp(node), coordTimes.length ? {
-        coordinateProperties: {
-          times: coordTimes.length === 1 ? coordTimes[0] : coordTimes
-        }
-      } : {})
-    };
-    if (feature3.properties?.visibility !== void 0) {
-      feature3.properties.visibility = feature3.properties.visibility !== "0";
+    function revalidateProvisionalEntities(cache) {
+      if (!cache.provisionalEntityIDs.size) return;
+      const handle = window.setTimeout(() => {
+        _deferredST.delete(handle);
+        if (!cache.provisionalEntityIDs.size) return;
+        validateEntitiesAsync(Array.from(cache.provisionalEntityIDs), cache);
+      }, RETRY);
+      _deferredST.add(handle);
     }
-    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;
-    if (!id2 && isElement(parentNode) && parentNode.localName === "CascadingStyle") {
-      id2 = parentNode.getAttribute("kml:id") || parentNode.getAttribute("id");
+    function processQueue(cache) {
+      if (!cache.queue.length) return Promise.resolve();
+      const chunk = cache.queue.pop();
+      return new Promise((resolvePromise, rejectPromise) => {
+        const handle = window.requestIdleCallback(() => {
+          delete _deferredRIC[handle];
+          chunk.forEach((job) => job());
+          resolvePromise();
+        });
+        _deferredRIC[handle] = rejectPromise;
+      }).then(() => {
+        if (cache.queue.length % 25 === 0) dispatch14.call("validated");
+      }).then(() => processQueue(cache));
     }
-    return normalizeId(id2 || "");
+    return validator;
   }
-  function buildStyleMap(node) {
-    const styleMap = {};
-    for (const style of $(node, "Style")) {
-      styleMap[getStyleId(style)] = extractStyle(style);
-    }
-    for (const map2 of $(node, "StyleMap")) {
-      const id2 = normalizeId(map2.getAttribute("id") || "");
-      val1(map2, "styleUrl", (styleUrl) => {
-        styleUrl = normalizeId(styleUrl);
-        if (styleMap[styleUrl]) {
-          styleMap[id2] = styleMap[styleUrl];
+  function validationCache(which) {
+    let cache = {
+      which,
+      graph: null,
+      queue: [],
+      queuePromise: null,
+      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) => {
+        if (!cache.issuesByEntityID[entityID]) {
+          cache.issuesByEntityID[entityID] = /* @__PURE__ */ new Set();
         }
+        cache.issuesByEntityID[entityID].add(issue.id);
       });
-    }
-    return styleMap;
-  }
-  function* kmlGen(node) {
-    const styleMap = buildStyleMap(node);
-    for (const placemark of $(node, "Placemark")) {
-      const feature3 = getPlacemark(placemark, styleMap);
-      if (feature3)
-        yield feature3;
-    }
-  }
-  function kml(node) {
-    return {
-      type: "FeatureCollection",
-      features: Array.from(kmlGen(node))
+      cache.issuesByIssueID[issue.id] = issue;
+    };
+    cache.uncacheIssue = (issue) => {
+      (issue.entityIds || []).forEach((entityID) => {
+        if (cache.issuesByEntityID[entityID]) {
+          cache.issuesByEntityID[entityID].delete(issue.id);
+        }
+      });
+      delete cache.issuesByIssueID[issue.id];
+    };
+    cache.cacheIssues = (issues) => {
+      issues.forEach(cache.cacheIssue);
+    };
+    cache.uncacheIssues = (issues) => {
+      issues.forEach(cache.uncacheIssue);
+    };
+    cache.uncacheIssuesOfType = (type2) => {
+      const issuesOfType = Object.values(cache.issuesByIssueID).filter((issue) => issue.type === type2);
+      cache.uncacheIssues(issuesOfType);
+    };
+    cache.uncacheEntityID = (entityID) => {
+      const entityIssueIDs = cache.issuesByEntityID[entityID];
+      if (entityIssueIDs) {
+        entityIssueIDs.forEach((issueID) => {
+          const issue = cache.issuesByIssueID[issueID];
+          if (issue) {
+            cache.uncacheIssue(issue);
+          } else {
+            delete cache.issuesByIssueID[issueID];
+          }
+        });
+      }
+      delete cache.issuesByEntityID[entityID];
+      cache.provisionalEntityIDs.delete(entityID);
+    };
+    cache.withAllRelatedEntities = (entityIDs) => {
+      let result = /* @__PURE__ */ new Set();
+      (entityIDs || []).forEach((entityID) => {
+        result.add(entityID);
+        const entityIssueIDs = cache.issuesByEntityID[entityID];
+        if (entityIssueIDs) {
+          entityIssueIDs.forEach((issueID) => {
+            const issue = cache.issuesByIssueID[issueID];
+            if (issue) {
+              (issue.entityIds || []).forEach((relatedID) => result.add(relatedID));
+            } else {
+              delete cache.issuesByIssueID[issueID];
+            }
+          });
+        }
+      });
+      return result;
     };
+    return cache;
   }
 
-  // modules/svg/data.js
-  var _initialized = false;
-  var _enabled = false;
-  var _geojson;
-  function svgData(projection2, context, dispatch10) {
-    var throttledRedraw = throttle_default(function() {
-      dispatch10.call("change");
-    }, 1e3);
-    var _showLabels = true;
-    var detected = utilDetect();
-    var layer = select_default2(null);
-    var _vtService;
-    var _fileList;
-    var _template;
-    var _src;
-    function init2() {
-      if (_initialized)
+  // modules/core/uploader.js
+  function coreUploader(context) {
+    var dispatch14 = 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 = [];
+    var _errors = [];
+    var _origChanges;
+    var _discardTags = {};
+    _mainFileFetcher.get("discarded").then(function(d2) {
+      _discardTags = d2;
+    }).catch(function() {
+    });
+    var uploader = utilRebind({}, dispatch14, "on");
+    uploader.isSaving = function() {
+      return _isSaving;
+    };
+    uploader.save = function(changeset, tryAgain, checkConflicts) {
+      if (_isSaving && !tryAgain) {
         return;
-      _geojson = {};
-      _enabled = true;
-      function over(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        d3_event.dataTransfer.dropEffect = "copy";
       }
-      context.container().attr("dropzone", "copy").on("drop.svgData", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        if (!detected.filedrop)
-          return;
-        drawData.fileList(d3_event.dataTransfer.files);
-      }).on("dragenter.svgData", over).on("dragexit.svgData", over).on("dragover.svgData", over);
-      _initialized = true;
-    }
-    function getService() {
-      if (services.vectorTile && !_vtService) {
-        _vtService = services.vectorTile;
-        _vtService.event.on("loadedData", throttledRedraw);
-      } else if (!services.vectorTile && _vtService) {
-        _vtService = null;
+      var osm = context.connection();
+      if (!osm) return;
+      if (!osm.authenticated()) {
+        osm.authenticate(function(err) {
+          if (!err) {
+            uploader.save(changeset, tryAgain, checkConflicts);
+          }
+        });
+        return;
       }
-      return _vtService;
-    }
-    function showLayer() {
-      layerOn();
-      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
-        dispatch10.call("change");
-      });
-    }
-    function hideLayer() {
-      throttledRedraw.cancel();
-      layer.transition().duration(250).style("opacity", 0).on("end", layerOff);
-    }
-    function layerOn() {
-      layer.style("display", "block");
-    }
-    function layerOff() {
-      layer.selectAll(".viewfield-group").remove();
-      layer.style("display", "none");
-    }
-    function ensureIDs(gj) {
-      if (!gj)
-        return null;
-      if (gj.type === "FeatureCollection") {
-        for (var i2 = 0; i2 < gj.features.length; i2++) {
-          ensureFeatureID(gj.features[i2]);
-        }
-      } else {
-        ensureFeatureID(gj);
+      if (!_isSaving) {
+        _isSaving = true;
+        dispatch14.call("saveStarted", this);
       }
-      return gj;
-    }
-    function ensureFeatureID(feature3) {
-      if (!feature3)
-        return;
-      feature3.__featurehash__ = utilHashcode((0, import_fast_json_stable_stringify.default)(feature3));
-      return feature3;
-    }
-    function getFeatures(gj) {
-      if (!gj)
-        return [];
-      if (gj.type === "FeatureCollection") {
-        return gj.features;
+      var history = context.history();
+      _conflicts = [];
+      _errors = [];
+      _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags));
+      if (!tryAgain) {
+        history.perform(actionNoop());
+      }
+      if (!checkConflicts) {
+        upload(changeset);
       } else {
-        return [gj];
+        performFullConflictCheck(changeset);
       }
-    }
-    function featureKey(d) {
-      return d.__featurehash__;
-    }
-    function isPolygon(d) {
-      return d.geometry.type === "Polygon" || d.geometry.type === "MultiPolygon";
-    }
-    function clipPathID(d) {
-      return "ideditor-data-" + d.__featurehash__ + "-clippath";
-    }
-    function featureClasses(d) {
-      return [
-        "data" + d.__featurehash__,
-        d.geometry.type,
-        isPolygon(d) ? "area" : "",
-        d.__layerID__ || ""
-      ].filter(Boolean).join(" ");
-    }
-    function drawData(selection2) {
-      var vtService = getService();
-      var getPath = svgPath(projection2).geojson;
-      var getAreaPath = svgPath(projection2, null, true).geojson;
-      var hasData = drawData.hasData();
-      layer = selection2.selectAll(".layer-mapdata").data(_enabled && hasData ? [0] : []);
-      layer.exit().remove();
-      layer = layer.enter().append("g").attr("class", "layer-mapdata").merge(layer);
-      var surface = context.surface();
-      if (!surface || surface.empty())
-        return;
-      var geoData, polygonData;
-      if (_template && vtService) {
-        var sourceID = _template;
-        vtService.loadTiles(sourceID, _template, projection2);
-        geoData = vtService.data(sourceID, projection2);
+    };
+    function performFullConflictCheck(changeset) {
+      var osm = context.connection();
+      if (!osm) return;
+      var history = context.history();
+      var localGraph = context.graph();
+      var remoteGraph = coreGraph(history.base(), true);
+      var summary = history.difference().summary();
+      var _toCheck = [];
+      for (var i3 = 0; i3 < summary.length; i3++) {
+        var item = summary[i3];
+        if (item.changeType === "modified") {
+          _toCheck.push(item.entity.id);
+        }
+      }
+      var _toLoad = withChildNodes(_toCheck, localGraph);
+      var _loaded = {};
+      var _toLoadCount = 0;
+      var _toLoadTotal = _toLoad.length;
+      if (_toCheck.length) {
+        dispatch14.call("progressChanged", this, _toLoadCount, _toLoadTotal);
+        _toLoad.forEach(function(id2) {
+          _loaded[id2] = false;
+        });
+        osm.loadMultiple(_toLoad, loaded);
       } else {
-        geoData = getFeatures(_geojson);
+        upload(changeset);
       }
-      geoData = geoData.filter(getPath);
-      polygonData = geoData.filter(isPolygon);
-      var clipPaths = surface.selectAll("defs").selectAll(".clipPath-data").data(polygonData, featureKey);
-      clipPaths.exit().remove();
-      var clipPathsEnter = clipPaths.enter().append("clipPath").attr("class", "clipPath-data").attr("id", clipPathID);
-      clipPathsEnter.append("path");
-      clipPaths.merge(clipPathsEnter).selectAll("path").attr("d", getAreaPath);
-      var datagroups = layer.selectAll("g.datagroup").data(["fill", "shadow", "stroke"]);
-      datagroups = datagroups.enter().append("g").attr("class", function(d) {
-        return "datagroup datagroup-" + d;
-      }).merge(datagroups);
-      var pathData = {
-        fill: polygonData,
-        shadow: geoData,
-        stroke: geoData
-      };
-      var paths = datagroups.selectAll("path").data(function(layer2) {
-        return pathData[layer2];
-      }, featureKey);
-      paths.exit().remove();
-      paths = paths.enter().append("path").attr("class", function(d) {
-        var datagroup = this.parentNode.__data__;
-        return "pathdata " + datagroup + " " + featureClasses(d);
-      }).attr("clip-path", function(d) {
-        var datagroup = this.parentNode.__data__;
-        return datagroup === "fill" ? "url(#" + clipPathID(d) + ")" : null;
-      }).merge(paths).attr("d", function(d) {
-        var datagroup = this.parentNode.__data__;
-        return datagroup === "fill" ? getAreaPath(d) : getPath(d);
-      });
-      layer.call(drawLabels, "label-halo", geoData).call(drawLabels, "label", geoData);
-      function drawLabels(selection3, textClass, data) {
-        var labelPath = path_default(projection2);
-        var labelData = data.filter(function(d) {
-          return _showLabels && d.properties && (d.properties.desc || d.properties.name);
+      return;
+      function withChildNodes(ids, graph) {
+        var s2 = new Set(ids);
+        ids.forEach(function(id2) {
+          var entity = graph.entity(id2);
+          if (entity.type !== "way") return;
+          graph.childNodes(entity).forEach(function(child) {
+            if (child.version !== void 0) {
+              s2.add(child.id);
+            }
+          });
         });
-        var labels = selection3.selectAll("text." + textClass).data(labelData, featureKey);
-        labels.exit().remove();
-        labels = labels.enter().append("text").attr("class", function(d) {
-          return textClass + " " + featureClasses(d);
-        }).merge(labels).text(function(d) {
-          return d.properties.desc || d.properties.name;
-        }).attr("x", function(d) {
-          var centroid = labelPath.centroid(d);
-          return centroid[0] + 11;
-        }).attr("y", function(d) {
-          var centroid = labelPath.centroid(d);
-          return centroid[1];
+        return Array.from(s2);
+      }
+      function loaded(err, result) {
+        if (_errors.length) return;
+        if (err) {
+          _errors.push({
+            msg: err.message || err.responseText,
+            details: [_t("save.status_code", { code: err.status })]
+          });
+          didResultInErrors();
+        } else {
+          var loadMore = [];
+          result.data.forEach(function(entity) {
+            remoteGraph.replace(entity);
+            _loaded[entity.id] = true;
+            _toLoad = _toLoad.filter(function(val) {
+              return val !== entity.id;
+            });
+            if (!entity.visible) return;
+            var i4, id2;
+            if (entity.type === "way") {
+              for (i4 = 0; i4 < entity.nodes.length; i4++) {
+                id2 = entity.nodes[i4];
+                if (_loaded[id2] === void 0) {
+                  _loaded[id2] = false;
+                  loadMore.push(id2);
+                }
+              }
+            } else if (entity.type === "relation" && entity.isMultipolygon()) {
+              for (i4 = 0; i4 < entity.members.length; i4++) {
+                id2 = entity.members[i4].id;
+                if (_loaded[id2] === void 0) {
+                  _loaded[id2] = false;
+                  loadMore.push(id2);
+                }
+              }
+            }
+          });
+          _toLoadCount += result.data.length;
+          _toLoadTotal += loadMore.length;
+          dispatch14.call("progressChanged", this, _toLoadCount, _toLoadTotal);
+          if (loadMore.length) {
+            _toLoad.push.apply(_toLoad, loadMore);
+            osm.loadMultiple(loadMore, loaded);
+          }
+          if (!_toLoad.length) {
+            detectConflicts();
+            upload(changeset);
+          }
+        }
+      }
+      function detectConflicts() {
+        function choice(id2, text, action) {
+          return {
+            id: id2,
+            text,
+            action: function() {
+              history.replace(action);
+            }
+          };
+        }
+        function formatUser(d2) {
+          return '<a href="' + osm.userURL(d2) + '" target="_blank">' + escape_default(d2) + "</a>";
+        }
+        function entityName(entity) {
+          return utilDisplayName(entity) || utilDisplayType(entity.id) + " " + entity.id;
+        }
+        function sameVersions(local, remote) {
+          if (local.version !== remote.version) return false;
+          if (local.type === "way") {
+            var children2 = utilArrayUnion(local.nodes, remote.nodes);
+            for (var i4 = 0; i4 < children2.length; i4++) {
+              var a2 = localGraph.hasEntity(children2[i4]);
+              var b2 = remoteGraph.hasEntity(children2[i4]);
+              if (a2 && b2 && a2.version !== b2.version) return false;
+            }
+          }
+          return true;
+        }
+        _toCheck.forEach(function(id2) {
+          var local = localGraph.entity(id2);
+          var remote = remoteGraph.entity(id2);
+          if (sameVersions(local, remote)) return;
+          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");
+          var forceRemote = actionMergeRemoteChanges(id2, localGraph, remoteGraph, _discardTags).withOption("force_remote");
+          var keepMine = _t("save.conflict." + (remote.visible ? "keep_local" : "restore"));
+          var keepTheirs = _t("save.conflict." + (remote.visible ? "keep_remote" : "delete"));
+          _conflicts.push({
+            id: id2,
+            name: entityName(local),
+            details: mergeConflicts,
+            chosen: 1,
+            choices: [
+              choice(id2, keepMine, forceLocal),
+              choice(id2, keepTheirs, forceRemote)
+            ]
+          });
         });
       }
     }
-    function getExtension(fileName) {
-      if (!fileName)
-        return;
-      var re2 = /\.(gpx|kml|(geo)?json)$/i;
-      var match = fileName.toLowerCase().match(re2);
-      return match && match.length && match[0];
-    }
-    function xmlToDom(textdata) {
-      return new DOMParser().parseFromString(textdata, "text/xml");
+    function upload(changeset) {
+      var osm = context.connection();
+      if (!osm) {
+        _errors.push({ msg: "No OSM Service" });
+      }
+      if (_conflicts.length) {
+        didResultInConflicts(changeset);
+      } else if (_errors.length) {
+        didResultInErrors();
+      } else {
+        var history = context.history();
+        var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
+        if (changes.modified.length || changes.created.length || changes.deleted.length) {
+          dispatch14.call("willAttemptUpload", this);
+          osm.putChangeset(changeset, changes, uploadCallback);
+        } else {
+          didResultInNoChanges();
+        }
+      }
     }
-    function stringifyGeojsonProperties(feature3) {
-      const properties = feature3.properties;
-      for (const key in properties) {
-        const property = properties[key];
-        if (typeof property === "number" || typeof property === "boolean" || Array.isArray(property)) {
-          properties[key] = property.toString();
-        } else if (property === null) {
-          properties[key] = "null";
-        } else if (typeof property === "object") {
-          properties[key] = JSON.stringify(property);
+    function uploadCallback(err, changeset) {
+      if (err) {
+        if (err.status === 409) {
+          uploader.save(changeset, true, true);
+        } else {
+          _errors.push({
+            msg: err.message || err.responseText,
+            details: [_t("save.status_code", { code: err.status })]
+          });
+          didResultInErrors();
         }
+      } else {
+        didResultInSuccess(changeset);
       }
     }
-    drawData.setFile = function(extension, data) {
-      _template = null;
-      _fileList = null;
-      _geojson = null;
-      _src = null;
-      var gj;
-      switch (extension) {
-        case ".gpx":
-          gj = gpx(xmlToDom(data));
-          break;
-        case ".kml":
-          gj = kml(xmlToDom(data));
-          break;
-        case ".geojson":
-        case ".json":
-          gj = JSON.parse(data);
-          if (gj.type === "FeatureCollection") {
-            gj.features.forEach(stringifyGeojsonProperties);
-          } else if (gj.type === "Feature") {
-            stringifyGeojsonProperties(gj);
+    function didResultInNoChanges() {
+      dispatch14.call("resultNoChanges", this);
+      endSave();
+      context.flush();
+    }
+    function didResultInErrors() {
+      context.history().pop();
+      dispatch14.call("resultErrors", this, _errors);
+      endSave();
+    }
+    function didResultInConflicts(changeset) {
+      _conflicts.sort(function(a2, b2) {
+        return b2.id.localeCompare(a2.id);
+      });
+      dispatch14.call("resultConflicts", this, changeset, _conflicts, _origChanges);
+      endSave();
+    }
+    function didResultInSuccess(changeset) {
+      context.history().clearSaved();
+      dispatch14.call("resultSuccess", this, changeset);
+      window.setTimeout(function() {
+        endSave();
+        context.flush();
+      }, 2500);
+    }
+    function endSave() {
+      _isSaving = false;
+      dispatch14.call("saveEnded", this);
+    }
+    uploader.cancelConflictResolution = function() {
+      context.history().pop();
+    };
+    uploader.processResolvedConflicts = function(changeset) {
+      var history = context.history();
+      for (var i3 = 0; i3 < _conflicts.length; i3++) {
+        if (_conflicts[i3].chosen === 1) {
+          var entity = context.hasEntity(_conflicts[i3].id);
+          if (entity && entity.type === "way") {
+            var children2 = utilArrayUniq(entity.nodes);
+            for (var j2 = 0; j2 < children2.length; j2++) {
+              history.replace(actionRevert(children2[j2]));
+            }
           }
-          break;
-      }
-      gj = gj || {};
-      if (Object.keys(gj).length) {
-        _geojson = ensureIDs(gj);
-        _src = extension + " data file";
-        this.fitZoom();
+          history.replace(actionRevert(_conflicts[i3].id));
+        }
       }
-      dispatch10.call("change");
-      return this;
-    };
-    drawData.showLabels = function(val) {
-      if (!arguments.length)
-        return _showLabels;
-      _showLabels = val;
-      return this;
+      uploader.save(changeset, true, false);
     };
-    drawData.enabled = function(val) {
-      if (!arguments.length)
-        return _enabled;
-      _enabled = val;
-      if (_enabled) {
-        showLayer();
-      } else {
-        hideLayer();
-      }
-      dispatch10.call("change");
-      return this;
+    uploader.reset = function() {
     };
-    drawData.hasData = function() {
-      var gj = _geojson || {};
-      return !!(_template || Object.keys(gj).length);
+    return uploader;
+  }
+
+  // modules/modes/draw_area.js
+  function modeDrawArea(context, wayID, startGraph, button) {
+    var mode = {
+      button,
+      id: "draw-area"
     };
-    drawData.template = function(val, src) {
-      if (!arguments.length)
-        return _template;
-      var osm = context.connection();
-      if (osm) {
-        var blocklists = osm.imageryBlocklists();
-        var fail = false;
-        var tested = 0;
-        var regex;
-        for (var i2 = 0; i2 < blocklists.length; i2++) {
-          regex = blocklists[i2];
-          fail = regex.test(val);
-          tested++;
-          if (fail)
-            break;
-        }
-        if (!tested) {
-          regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
-          fail = regex.test(val);
-        }
-      }
-      _template = val;
-      _fileList = null;
-      _geojson = null;
-      _src = src || "vectortile:" + val.split(/[?#]/)[0];
-      dispatch10.call("change");
-      return this;
+    var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on("rejectedSelfIntersection.modeDrawArea", function() {
+      context.ui().flash.iconName("#iD-icon-no").label(_t.append("self_intersection.error.areas"))();
+    });
+    mode.wayID = wayID;
+    mode.enter = function() {
+      context.install(behavior);
     };
-    drawData.geojson = function(gj, src) {
-      if (!arguments.length)
-        return _geojson;
-      _template = null;
-      _fileList = null;
-      _geojson = null;
-      _src = null;
-      gj = gj || {};
-      if (Object.keys(gj).length) {
-        _geojson = ensureIDs(gj);
-        _src = src || "unknown.geojson";
-      }
-      dispatch10.call("change");
-      return this;
+    mode.exit = function() {
+      context.uninstall(behavior);
     };
-    drawData.fileList = function(fileList) {
-      if (!arguments.length)
-        return _fileList;
-      _template = null;
-      _fileList = fileList;
-      _geojson = null;
-      _src = null;
-      if (!fileList || !fileList.length)
-        return this;
-      var f2 = fileList[0];
-      var extension = getExtension(f2.name);
-      var reader = new FileReader();
-      reader.onload = function() {
-        return function(e) {
-          drawData.setFile(extension, e.target.result);
-        };
-      }(f2);
-      reader.readAsText(f2);
-      return this;
+    mode.selectedIDs = function() {
+      return [wayID];
     };
-    drawData.url = function(url, defaultExtension) {
-      _template = null;
-      _fileList = null;
-      _geojson = null;
-      _src = null;
-      var testUrl = url.split(/[?#]/)[0];
-      var extension = getExtension(testUrl) || defaultExtension;
-      if (extension) {
-        _template = null;
-        text_default3(url).then(function(data) {
-          drawData.setFile(extension, data);
-        }).catch(function() {
-        });
-      } else {
-        drawData.template(url);
-      }
-      return this;
+    mode.activeID = function() {
+      return behavior && behavior.activeID() || [];
     };
-    drawData.getSrc = function() {
-      return _src || "";
+    return mode;
+  }
+
+  // modules/modes/add_area.js
+  function modeAddArea(context, mode) {
+    mode.id = "add-area";
+    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
+    function defaultTags(loc) {
+      var defaultTags2 = { area: "yes" };
+      if (mode.preset) defaultTags2 = mode.preset.setTags(defaultTags2, "area", false, loc);
+      return defaultTags2;
+    }
+    function actionClose(wayId) {
+      return function(graph) {
+        return graph.replace(graph.entity(wayId).close());
+      };
+    }
+    function start2(loc) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionClose(way.id)
+      );
+      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    }
+    function startFromWay(loc, edge) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionClose(way.id),
+        actionAddMidpoint({ loc, edge }, node)
+      );
+      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    }
+    function startFromNode(node) {
+      var startGraph = context.graph();
+      var way = osmWay({ tags: defaultTags(node.loc) });
+      context.perform(
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionClose(way.id)
+      );
+      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    }
+    mode.enter = function() {
+      context.install(behavior);
     };
-    drawData.fitZoom = function() {
-      var features2 = getFeatures(_geojson);
-      if (!features2.length)
-        return;
-      var map2 = context.map();
-      var viewport = map2.trimmedExtent().polygon();
-      var coords = features2.reduce(function(coords2, feature3) {
-        var geom = feature3.geometry;
-        if (!geom)
-          return coords2;
-        var c = geom.coordinates;
-        switch (geom.type) {
-          case "Point":
-            c = [c];
-          case "MultiPoint":
-          case "LineString":
-            break;
-          case "MultiPolygon":
-            c = utilArrayFlatten(c);
-          case "Polygon":
-          case "MultiLineString":
-            c = utilArrayFlatten(c);
-            break;
-        }
-        return utilArrayUnion(coords2, c);
-      }, []);
-      if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
-        var extent = geoExtent(bounds_default({ type: "LineString", coordinates: coords }));
-        map2.centerZoom(extent.center(), map2.trimmedExtentZoom(extent));
-      }
-      return this;
+    mode.exit = function() {
+      context.uninstall(behavior);
     };
-    init2();
-    return drawData;
+    return mode;
   }
 
-  // modules/svg/debug.js
-  function svgDebug(projection2, context) {
-    function drawDebug(selection2) {
-      const showTile = context.getDebug("tile");
-      const showCollision = context.getDebug("collision");
-      const showImagery = context.getDebug("imagery");
-      const showTouchTargets = context.getDebug("target");
-      const showDownloaded = context.getDebug("downloaded");
-      let debugData = [];
-      if (showTile) {
-        debugData.push({ class: "red", label: "tile" });
-      }
-      if (showCollision) {
-        debugData.push({ class: "yellow", label: "collision" });
-      }
-      if (showImagery) {
-        debugData.push({ class: "orange", label: "imagery" });
-      }
-      if (showTouchTargets) {
-        debugData.push({ class: "pink", label: "touchTargets" });
-      }
-      if (showDownloaded) {
-        debugData.push({ class: "purple", label: "downloaded" });
-      }
-      let legend = context.container().select(".main-content").selectAll(".debug-legend").data(debugData.length ? [0] : []);
-      legend.exit().remove();
-      legend = legend.enter().append("div").attr("class", "fillD debug-legend").merge(legend);
-      let legendItems = legend.selectAll(".debug-legend-item").data(debugData, (d) => d.label);
-      legendItems.exit().remove();
-      legendItems.enter().append("span").attr("class", (d) => `debug-legend-item ${d.class}`).text((d) => d.label);
-      let layer = selection2.selectAll(".layer-debug").data(showImagery || showDownloaded ? [0] : []);
-      layer.exit().remove();
-      layer = layer.enter().append("g").attr("class", "layer-debug").merge(layer);
-      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);
-        imagery.exit().remove();
-        imagery.enter().append("path").attr("class", "debug-imagery debug orange");
-      }).catch(() => {
-      });
-      const osm = context.connection();
-      let dataDownloaded = [];
-      if (osm && showDownloaded) {
-        const rtree = osm.caches("get").tile.rtree;
-        dataDownloaded = rtree.all().map((bbox) => {
-          return {
-            type: "Feature",
-            properties: { id: bbox.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]
-              ]]
-            }
-          };
-        });
-      }
-      let downloaded = layer.selectAll("path.debug-downloaded").data(showDownloaded ? dataDownloaded : []);
-      downloaded.exit().remove();
-      downloaded.enter().append("path").attr("class", "debug-downloaded debug purple");
-      layer.selectAll("path").attr("d", svgPath(projection2).geojson);
+  // modules/modes/add_line.js
+  function modeAddLine(context, mode) {
+    mode.id = "add-line";
+    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
+    function defaultTags(loc) {
+      var defaultTags2 = {};
+      if (mode.preset) defaultTags2 = mode.preset.setTags(defaultTags2, "line", false, loc);
+      return defaultTags2;
     }
-    drawDebug.enabled = function() {
-      if (!arguments.length) {
-        return context.getDebug("tile") || context.getDebug("collision") || context.getDebug("imagery") || context.getDebug("target") || context.getDebug("downloaded");
-      } else {
-        return this;
-      }
+    function start2(loc) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id)
+      );
+      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    }
+    function startFromWay(loc, edge) {
+      var startGraph = context.graph();
+      var node = osmNode({ loc });
+      var way = osmWay({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id),
+        actionAddMidpoint({ loc, edge }, node)
+      );
+      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    }
+    function startFromNode(node) {
+      var startGraph = context.graph();
+      var way = osmWay({ tags: defaultTags(node.loc) });
+      context.perform(
+        actionAddEntity(way),
+        actionAddVertex(way.id, node.id)
+      );
+      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+    }
+    mode.enter = function() {
+      context.install(behavior);
     };
-    return drawDebug;
+    mode.exit = function() {
+      context.uninstall(behavior);
+    };
+    return mode;
   }
 
-  // modules/svg/defs.js
-  function svgDefs(context) {
-    var _defsSelection = select_default2(null);
-    var _spritesheetIds = [
-      "iD-sprite",
-      "maki-sprite",
-      "temaki-sprite",
-      "fa-sprite",
-      "community-sprite"
-    ];
-    function drawDefs(selection2) {
-      _defsSelection = selection2.append("defs");
-      _defsSelection.append("marker").attr("id", "ideditor-oneway-marker").attr("viewBox", "0 0 10 5").attr("refX", 2.5).attr("refY", 2.5).attr("markerWidth", 2).attr("markerHeight", 2).attr("markerUnits", "strokeWidth").attr("orient", "auto").append("path").attr("class", "oneway-marker-path").attr("d", "M 5,3 L 0,3 L 0,2 L 5,2 L 5,0 L 10,2.5 L 5,5 z").attr("stroke", "none").attr("fill", "#000").attr("opacity", "0.75");
-      function addSidedMarker(name, color2, offset) {
-        _defsSelection.append("marker").attr("id", "ideditor-sided-marker-" + name).attr("viewBox", "0 0 2 2").attr("refX", 1).attr("refY", -offset).attr("markerWidth", 1.5).attr("markerHeight", 1.5).attr("markerUnits", "strokeWidth").attr("orient", "auto").append("path").attr("class", "sided-marker-path sided-marker-" + name + "-path").attr("d", "M 0,0 L 1,1 L 2,0 z").attr("stroke", "none").attr("fill", color2);
-      }
-      addSidedMarker("natural", "rgb(170, 170, 170)", 0);
-      addSidedMarker("coastline", "#77dede", 1);
-      addSidedMarker("waterway", "#77dede", 1);
-      addSidedMarker("barrier", "#ddd", 1);
-      addSidedMarker("man_made", "#fff", 0);
-      _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([
-        ["beach", "dots"],
-        ["construction", "construction"],
-        ["cemetery", "cemetery"],
-        ["cemetery_christian", "cemetery_christian"],
-        ["cemetery_buddhist", "cemetery_buddhist"],
-        ["cemetery_muslim", "cemetery_muslim"],
-        ["cemetery_jewish", "cemetery_jewish"],
-        ["farmland", "farmland"],
-        ["farmyard", "farmyard"],
-        ["forest", "forest"],
-        ["forest_broadleaved", "forest_broadleaved"],
-        ["forest_needleleaved", "forest_needleleaved"],
-        ["forest_leafless", "forest_leafless"],
-        ["golf_green", "grass"],
-        ["grass", "grass"],
-        ["landfill", "landfill"],
-        ["meadow", "grass"],
-        ["orchard", "orchard"],
-        ["pond", "pond"],
-        ["quarry", "quarry"],
-        ["scrub", "bushes"],
-        ["vineyard", "vineyard"],
-        ["water_standing", "lines"],
-        ["waves", "waves"],
-        ["wetland", "wetland"],
-        ["wetland_marsh", "wetland_marsh"],
-        ["wetland_swamp", "wetland_swamp"],
-        ["wetland_bog", "wetland_bog"],
-        ["wetland_reedbed", "wetland_reedbed"]
-      ]).enter().append("pattern").attr("id", function(d) {
-        return "ideditor-pattern-" + d[0];
-      }).attr("width", 32).attr("height", 32).attr("patternUnits", "userSpaceOnUse");
-      patterns2.append("rect").attr("x", 0).attr("y", 0).attr("width", 32).attr("height", 32).attr("class", function(d) {
-        return "pattern-color-" + d[0];
-      });
-      patterns2.append("image").attr("x", 0).attr("y", 0).attr("width", 32).attr("height", 32).attr("xlink:href", function(d) {
-        return context.imagePath("pattern/" + d[1] + ".png");
-      });
-      _defsSelection.selectAll("clipPath").data([12, 18, 20, 32, 45]).enter().append("clipPath").attr("id", function(d) {
-        return "ideditor-clip-square-" + d;
-      }).append("rect").attr("x", 0).attr("y", 0).attr("width", function(d) {
-        return d;
-      }).attr("height", function(d) {
-        return d;
-      });
-      addSprites(_spritesheetIds, true);
-    }
-    function addSprites(ids, overrideColors) {
-      _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
-      var spritesheets = _defsSelection.selectAll(".spritesheet").data(_spritesheetIds);
-      spritesheets.enter().append("g").attr("class", function(d) {
-        return "spritesheet spritesheet-" + d;
-      }).each(function(d) {
-        var url = context.imagePath(d + ".svg");
-        var node = select_default2(this).node();
-        svg(url).then(function(svg2) {
-          node.appendChild(
-            select_default2(svg2.documentElement).attr("id", "ideditor-" + d).node()
-          );
-          if (overrideColors && d !== "iD-sprite") {
-            select_default2(node).selectAll("path").attr("fill", "currentColor");
-          }
-        }).catch(function() {
-        });
-      });
-      spritesheets.exit().remove();
-    }
-    drawDefs.addSprites = addSprites;
-    return drawDefs;
-  }
-
-  // modules/svg/keepRight.js
-  var _layerEnabled = false;
-  var _qaService;
-  function svgKeepRight(projection2, context, dispatch10) {
-    const throttledRedraw = throttle_default(() => dispatch10.call("change"), 1e3);
-    const minZoom3 = 12;
-    let touchLayer = select_default2(null);
-    let drawLayer = select_default2(null);
-    let layerVisible = false;
-    function markerPath(selection2, klass) {
-      selection2.attr("class", klass).attr("transform", "translate(-4, -24)").attr("d", "M11.6,6.2H7.1l1.4-5.1C8.6,0.6,8.1,0,7.5,0H2.2C1.7,0,1.3,0.3,1.3,0.8L0,10.2c-0.1,0.6,0.4,1.1,0.9,1.1h4.6l-1.8,7.6C3.6,19.4,4.1,20,4.7,20c0.3,0,0.6-0.2,0.8-0.5l6.9-11.9C12.7,7,12.3,6.2,11.6,6.2z");
-    }
-    function getService() {
-      if (services.keepRight && !_qaService) {
-        _qaService = services.keepRight;
-        _qaService.on("loaded", throttledRedraw);
-      } else if (!services.keepRight && _qaService) {
-        _qaService = null;
-      }
-      return _qaService;
-    }
-    function editOn() {
-      if (!layerVisible) {
-        layerVisible = true;
-        drawLayer.style("display", "block");
-      }
+  // modules/modes/add_point.js
+  function modeAddPoint(context, mode) {
+    mode.id = "add-point";
+    var behavior = behaviorDraw(context).on("click", add).on("clickWay", addWay).on("clickNode", addNode).on("cancel", cancel).on("finish", cancel);
+    function defaultTags(loc) {
+      var defaultTags2 = {};
+      if (mode.preset) defaultTags2 = mode.preset.setTags(defaultTags2, "point", false, loc);
+      return defaultTags2;
     }
-    function editOff() {
-      if (layerVisible) {
-        layerVisible = false;
-        drawLayer.style("display", "none");
-        drawLayer.selectAll(".qaItem.keepRight").remove();
-        touchLayer.selectAll(".qaItem.keepRight").remove();
-      }
+    function add(loc) {
+      var node = osmNode({ loc, tags: defaultTags(loc) });
+      context.perform(
+        actionAddEntity(node),
+        _t("operations.add.annotation.point")
+      );
+      enterSelectMode(node);
     }
-    function layerOn() {
-      editOn();
-      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", () => dispatch10.call("change"));
+    function addWay(loc, edge) {
+      var node = osmNode({ tags: defaultTags(loc) });
+      context.perform(
+        actionAddMidpoint({ loc, edge }, node),
+        _t("operations.add.annotation.vertex")
+      );
+      enterSelectMode(node);
     }
-    function layerOff() {
-      throttledRedraw.cancel();
-      drawLayer.interrupt();
-      touchLayer.selectAll(".qaItem.keepRight").remove();
-      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", () => {
-        editOff();
-        dispatch10.call("change");
-      });
+    function enterSelectMode(node) {
+      context.enter(
+        modeSelect(context, [node.id]).newFeature(true)
+      );
     }
-    function updateMarkers() {
-      if (!layerVisible || !_layerEnabled)
-        return;
-      const service = getService();
-      const selectedID = context.selectedErrorID();
-      const data = service ? service.getItems(projection2) : [];
-      const getTransform = svgPointTransform(projection2);
-      const markers = drawLayer.selectAll(".qaItem.keepRight").data(data, (d) => d.id);
-      markers.exit().remove();
-      const markersEnter = markers.enter().append("g").attr("class", (d) => `qaItem ${d.service} itemId-${d.id} itemType-${d.parentIssueType}`);
-      markersEnter.append("ellipse").attr("cx", 0.5).attr("cy", 1).attr("rx", 6.5).attr("ry", 3).attr("class", "stroke");
-      markersEnter.append("path").call(markerPath, "shadow");
-      markersEnter.append("use").attr("class", "qaItem-fill").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").attr("xlink:href", "#iD-icon-bolt");
-      markers.merge(markersEnter).sort(sortY).classed("selected", (d) => d.id === selectedID).attr("transform", getTransform);
-      if (touchLayer.empty())
+    function addNode(node) {
+      const _defaultTags = defaultTags(node.loc);
+      if (Object.keys(_defaultTags).length === 0) {
+        enterSelectMode(node);
         return;
-      const fillClass = context.getDebug("target") ? "pink " : "nocolor ";
-      const targets = touchLayer.selectAll(".qaItem.keepRight").data(data, (d) => d.id);
-      targets.exit().remove();
-      targets.enter().append("rect").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").merge(targets).sort(sortY).attr("class", (d) => `qaItem ${d.service} target ${fillClass} itemId-${d.id}`).attr("transform", getTransform);
-      function sortY(a, b) {
-        return a.id === selectedID ? 1 : b.id === selectedID ? -1 : a.severity === "error" && b.severity !== "error" ? 1 : b.severity === "error" && a.severity !== "error" ? -1 : b.loc[1] - a.loc[1];
-      }
-    }
-    function drawKeepRight(selection2) {
-      const service = getService();
-      const surface = context.surface();
-      if (surface && !surface.empty()) {
-        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
       }
-      drawLayer = selection2.selectAll(".layer-keepRight").data(service ? [0] : []);
-      drawLayer.exit().remove();
-      drawLayer = drawLayer.enter().append("g").attr("class", "layer-keepRight").style("display", _layerEnabled ? "block" : "none").merge(drawLayer);
-      if (_layerEnabled) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          service.loadIssues(projection2);
-          updateMarkers();
-        } else {
-          editOff();
-        }
+      var tags = Object.assign({}, node.tags);
+      for (var key in _defaultTags) {
+        tags[key] = _defaultTags[key];
       }
+      context.perform(
+        actionChangeTags(node.id, tags),
+        _t("operations.add.annotation.point")
+      );
+      enterSelectMode(node);
     }
-    drawKeepRight.enabled = function(val) {
-      if (!arguments.length)
-        return _layerEnabled;
-      _layerEnabled = val;
-      if (_layerEnabled) {
-        layerOn();
-      } else {
-        layerOff();
-        if (context.selectedErrorID()) {
-          context.enter(modeBrowse(context));
-        }
-      }
-      dispatch10.call("change");
-      return this;
+    function cancel() {
+      context.enter(modeBrowse(context));
+    }
+    mode.enter = function() {
+      context.install(behavior);
     };
-    drawKeepRight.supported = () => !!getService();
-    return drawKeepRight;
+    mode.exit = function() {
+      context.uninstall(behavior);
+    };
+    return mode;
   }
 
-  // modules/svg/geolocate.js
-  function svgGeolocate(projection2) {
-    var layer = select_default2(null);
-    var _position;
-    function init2() {
-      if (svgGeolocate.initialized)
-        return;
-      svgGeolocate.enabled = false;
-      svgGeolocate.initialized = true;
-    }
-    function showLayer() {
-      layer.style("display", "block");
-    }
-    function hideLayer() {
-      layer.transition().duration(250).style("opacity", 0);
-    }
-    function layerOn() {
-      layer.style("opacity", 0).transition().duration(250).style("opacity", 1);
-    }
-    function layerOff() {
-      layer.style("display", "none");
-    }
-    function transform2(d) {
-      return svgPointTransform(projection2)(d);
-    }
-    function accuracy(accuracy2, loc) {
-      var degreesRadius = geoMetersToLat(accuracy2), tangentLoc = [loc[0], loc[1] + degreesRadius], projectedTangent = projection2(tangentLoc), projectedLoc = projection2([loc[0], loc[1]]);
-      return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
+  // modules/ui/note_comments.js
+  function uiNoteComments() {
+    var _note;
+    function noteComments(selection2) {
+      if (_note.isNew()) return;
+      var comments = selection2.selectAll(".comments-container").data([0]);
+      comments = comments.enter().append("div").attr("class", "comments-container").merge(comments);
+      var commentEnter = comments.selectAll(".comment").data(_note.comments).enter().append("div").attr("class", "comment");
+      commentEnter.append("div").attr("class", function(d2) {
+        return "comment-avatar user-" + d2.uid;
+      }).call(svgIcon("#iD-icon-avatar", "comment-avatar-icon"));
+      var mainEnter = commentEnter.append("div").attr("class", "comment-main");
+      var metadataEnter = mainEnter.append("div").attr("class", "comment-metadata");
+      metadataEnter.append("div").attr("class", "comment-author").each(function(d2) {
+        var selection3 = select_default2(this);
+        var osm = services.osm;
+        if (osm && d2.user) {
+          selection3 = selection3.append("a").attr("class", "comment-author-link").attr("href", osm.userURL(d2.user)).attr("target", "_blank");
+        }
+        if (d2.user) {
+          selection3.text(d2.user);
+        } else {
+          selection3.call(_t.append("note.anonymous"));
+        }
+      });
+      metadataEnter.append("div").attr("class", "comment-date").html(function(d2) {
+        return _t.html("note.status." + d2.action, { when: localeDateString2(d2.date) });
+      });
+      mainEnter.append("div").attr("class", "comment-text").html(function(d2) {
+        return d2.html;
+      }).selectAll("a").attr("rel", "noopener nofollow").attr("target", "_blank");
+      comments.call(replaceAvatars);
     }
-    function update() {
-      var geolocation = { loc: [_position.coords.longitude, _position.coords.latitude] };
-      var groups = layer.selectAll(".geolocations").selectAll(".geolocation").data([geolocation]);
-      groups.exit().remove();
-      var pointsEnter = groups.enter().append("g").attr("class", "geolocation");
-      pointsEnter.append("circle").attr("class", "geolocate-radius").attr("dx", "0").attr("dy", "0").attr("fill", "rgb(15,128,225)").attr("fill-opacity", "0.3").attr("r", "0");
-      pointsEnter.append("circle").attr("dx", "0").attr("dy", "0").attr("fill", "rgb(15,128,225)").attr("stroke", "white").attr("stroke-width", "1.5").attr("r", "6");
-      groups.merge(pointsEnter).attr("transform", transform2);
-      layer.select(".geolocate-radius").attr("r", accuracy(_position.coords.accuracy, geolocation.loc));
+    function replaceAvatars(selection2) {
+      var showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
+      var osm = services.osm;
+      if (showThirdPartyIcons !== "true" || !osm) return;
+      var uids = {};
+      _note.comments.forEach(function(d2) {
+        if (d2.uid) uids[d2.uid] = true;
+      });
+      Object.keys(uids).forEach(function(uid) {
+        osm.loadUser(uid, function(err, user) {
+          if (!user || !user.image_url) return;
+          selection2.selectAll(".comment-avatar.user-" + uid).html("").append("img").attr("class", "icon comment-avatar-icon").attr("src", user.image_url).attr("alt", user.display_name);
+        });
+      });
     }
-    function drawLocation(selection2) {
-      var enabled = svgGeolocate.enabled;
-      layer = selection2.selectAll(".layer-geolocate").data([0]);
-      layer.exit().remove();
-      var layerEnter = layer.enter().append("g").attr("class", "layer-geolocate").style("display", enabled ? "block" : "none");
-      layerEnter.append("g").attr("class", "geolocations");
-      layer = layerEnter.merge(layer);
-      if (enabled) {
-        update();
-      } else {
-        layerOff();
-      }
+    function localeDateString2(s2) {
+      if (!s2) return null;
+      var options2 = { day: "numeric", month: "short", year: "numeric" };
+      s2 = s2.replace(/-/g, "/");
+      var d2 = new Date(s2);
+      if (isNaN(d2.getTime())) return null;
+      return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
     }
-    drawLocation.enabled = function(position, enabled) {
-      if (!arguments.length)
-        return svgGeolocate.enabled;
-      _position = position;
-      svgGeolocate.enabled = enabled;
-      if (svgGeolocate.enabled) {
-        showLayer();
-        layerOn();
-      } else {
-        hideLayer();
-      }
-      return this;
+    noteComments.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteComments;
     };
-    init2();
-    return drawLocation;
+    return noteComments;
   }
 
-  // modules/svg/labels.js
-  var import_rbush7 = __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 _textWidthCache = {};
-    var _entitybboxes = {};
-    var labelStack = [
-      ["line", "aeroway", "*", 12],
-      ["line", "highway", "motorway", 12],
-      ["line", "highway", "trunk", 12],
-      ["line", "highway", "primary", 12],
-      ["line", "highway", "secondary", 12],
-      ["line", "highway", "tertiary", 12],
-      ["line", "highway", "*", 12],
-      ["line", "railway", "*", 12],
-      ["line", "waterway", "*", 12],
-      ["area", "aeroway", "*", 12],
-      ["area", "amenity", "*", 12],
-      ["area", "building", "*", 12],
-      ["area", "historic", "*", 12],
-      ["area", "leisure", "*", 12],
-      ["area", "man_made", "*", 12],
-      ["area", "natural", "*", 12],
-      ["area", "shop", "*", 12],
-      ["area", "tourism", "*", 12],
-      ["area", "camp_site", "*", 12],
-      ["point", "aeroway", "*", 10],
-      ["point", "amenity", "*", 10],
-      ["point", "building", "*", 10],
-      ["point", "historic", "*", 10],
-      ["point", "leisure", "*", 10],
-      ["point", "man_made", "*", 10],
-      ["point", "natural", "*", 10],
-      ["point", "shop", "*", 10],
-      ["point", "tourism", "*", 10],
-      ["point", "camp_site", "*", 10],
-      ["line", "ref", "*", 12],
-      ["area", "ref", "*", 12],
-      ["point", "ref", "*", 10],
-      ["line", "name", "*", 12],
-      ["area", "name", "*", 12],
-      ["point", "name", "*", 10]
-    ];
-    function shouldSkipIcon(preset) {
-      var noIcons = ["building", "landuse", "natural"];
-      return noIcons.some(function(s) {
-        return preset.id.indexOf(s) >= 0;
+  // modules/ui/note_header.js
+  function uiNoteHeader() {
+    var _note;
+    function noteHeader(selection2) {
+      var header = selection2.selectAll(".note-header").data(
+        _note ? [_note] : [],
+        function(d2) {
+          return d2.status + d2.id;
+        }
+      );
+      header.exit().remove();
+      var headerEnter = header.enter().append("div").attr("class", "note-header");
+      var iconEnter = headerEnter.append("div").attr("class", function(d2) {
+        return "note-header-icon " + d2.status;
+      }).classed("new", function(d2) {
+        return d2.id < 0;
       });
-    }
-    function get4(array2, prop) {
-      return function(d, i2) {
-        return array2[i2][prop];
-      };
-    }
-    function textWidth(text2, size, elem) {
-      var c = _textWidthCache[size];
-      if (!c)
-        c = _textWidthCache[size] = {};
-      if (c[text2]) {
-        return c[text2];
-      } else if (elem) {
-        c[text2] = elem.getComputedTextLength();
-        return c[text2];
-      } else {
-        var str2 = encodeURIComponent(text2).match(/%[CDEFcdef]/g);
-        if (str2 === null) {
-          return size / 3 * 2 * text2.length;
+      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-note", "note-fill"));
+      iconEnter.each(function(d2) {
+        var statusIcon;
+        if (d2.id < 0) {
+          statusIcon = "#iD-icon-plus";
+        } else if (d2.status === "open") {
+          statusIcon = "#iD-icon-close";
         } else {
-          return size / 3 * (2 * text2.length + str2.length);
+          statusIcon = "#iD-icon-apply";
         }
-      }
-    }
-    function drawLinePaths(selection2, entities, filter2, classes, labels) {
-      var paths = selection2.selectAll("path").filter(filter2).data(entities, osmEntity.key);
-      paths.exit().remove();
-      paths.enter().append("path").style("stroke-width", get4(labels, "font-size")).attr("id", function(d) {
-        return "ideditor-labelpath-" + d.id;
-      }).attr("class", classes).merge(paths).attr("d", get4(labels, "lineString"));
-    }
-    function drawLineLabels(selection2, entities, filter2, classes, labels) {
-      var texts = selection2.selectAll("text." + classes).filter(filter2).data(entities, osmEntity.key);
-      texts.exit().remove();
-      texts.enter().append("text").attr("class", function(d, i2) {
-        return classes + " " + labels[i2].classes + " " + d.id;
-      }).attr("dy", baselineHack ? "0.35em" : null).append("textPath").attr("class", "textpath");
-      selection2.selectAll("text." + classes).selectAll(".textpath").filter(filter2).data(entities, osmEntity.key).attr("startOffset", "50%").attr("xlink:href", function(d) {
-        return "#ideditor-labelpath-" + d.id;
-      }).text(utilDisplayNameForPath);
-    }
-    function drawPointLabels(selection2, entities, filter2, classes, labels) {
-      var texts = selection2.selectAll("text." + classes).filter(filter2).data(entities, osmEntity.key);
-      texts.exit().remove();
-      texts.enter().append("text").attr("class", function(d, i2) {
-        return classes + " " + labels[i2].classes + " " + d.id;
-      }).merge(texts).attr("x", get4(labels, "x")).attr("y", get4(labels, "y")).style("text-anchor", get4(labels, "textAnchor")).text(utilDisplayName).each(function(d, i2) {
-        textWidth(utilDisplayName(d), labels[i2].height, this);
+        iconEnter.append("div").attr("class", "note-icon-annotation").attr("title", _t("icons.close")).call(svgIcon(statusIcon, "icon-annotation"));
+      });
+      headerEnter.append("div").attr("class", "note-header-label").html(function(d2) {
+        if (_note.isNew()) {
+          return _t.html("note.new");
+        }
+        return _t.html("note.note") + " " + d2.id + " " + (d2.status === "closed" ? _t.html("note.closed") : "");
       });
     }
-    function drawAreaLabels(selection2, entities, filter2, classes, labels) {
-      entities = entities.filter(hasText);
-      labels = labels.filter(hasText);
-      drawPointLabels(selection2, entities, filter2, classes, labels);
-      function hasText(d, i2) {
-        return labels[i2].hasOwnProperty("x") && labels[i2].hasOwnProperty("y");
+    noteHeader.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteHeader;
+    };
+    return noteHeader;
+  }
+
+  // modules/ui/note_report.js
+  function uiNoteReport() {
+    var _note;
+    function noteReport(selection2) {
+      var url;
+      if (services.osm && _note instanceof osmNote && !_note.isNew()) {
+        url = services.osm.noteReportURL(_note);
       }
+      var link3 = selection2.selectAll(".note-report").data(url ? [url] : []);
+      link3.exit().remove();
+      var linkEnter = link3.enter().append("a").attr("class", "note-report").attr("target", "_blank").attr("href", function(d2) {
+        return d2;
+      }).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("note.report"));
     }
-    function drawAreaIcons(selection2, entities, filter2, classes, labels) {
-      var icons = selection2.selectAll("use." + classes).filter(filter2).data(entities, osmEntity.key);
-      icons.exit().remove();
-      icons.enter().append("use").attr("class", "icon " + classes).attr("width", "17px").attr("height", "17px").merge(icons).attr("transform", get4(labels, "transform")).attr("xlink:href", function(d) {
-        var preset = _mainPresetIndex.match(d, context.graph());
-        var picon = preset && preset.icon;
-        return picon ? "#" + picon : "";
+    noteReport.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteReport;
+    };
+    return noteReport;
+  }
+
+  // modules/ui/view_on_osm.js
+  function uiViewOnOSM(context) {
+    var _what;
+    function viewOnOSM(selection2) {
+      var url;
+      if (_what instanceof osmEntity) {
+        url = context.connection().entityURL(_what);
+      } else if (_what instanceof osmNote) {
+        url = context.connection().noteURL(_what);
+      }
+      var data = !_what || _what.isNew() ? [] : [_what];
+      var link3 = selection2.selectAll(".view-on-osm").data(data, function(d2) {
+        return d2.id;
       });
+      link3.exit().remove();
+      var linkEnter = link3.enter().append("a").attr("class", "view-on-osm").attr("target", "_blank").attr("href", url).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("inspector.view_on_osm"));
     }
-    function drawCollisionBoxes(selection2, rtree, which) {
-      var classes = "debug " + which + " " + (which === "debug-skipped" ? "orange" : "yellow");
-      var gj = [];
-      if (context.getDebug("collision")) {
-        gj = rtree.all().map(function(d) {
-          return { type: "Polygon", coordinates: [[
-            [d.minX, d.minY],
-            [d.maxX, d.minY],
-            [d.maxX, d.maxY],
-            [d.minX, d.maxY],
-            [d.minX, d.minY]
-          ]] };
+    viewOnOSM.what = function(_2) {
+      if (!arguments.length) return _what;
+      _what = _2;
+      return viewOnOSM;
+    };
+    return viewOnOSM;
+  }
+
+  // modules/ui/note_editor.js
+  function uiNoteEditor(context) {
+    var dispatch14 = dispatch_default("change");
+    var noteComments = uiNoteComments(context);
+    var noteHeader = uiNoteHeader();
+    var _note;
+    var _newNote;
+    function noteEditor(selection2) {
+      var header = selection2.selectAll(".header").data([0]);
+      var headerEnter = header.enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
+        context.enter(modeBrowse(context));
+      }).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("note.title"));
+      var body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      var editor = body.selectAll(".note-editor").data([0]);
+      editor.enter().append("div").attr("class", "modal-section note-editor").merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
+      var footer = selection2.selectAll(".footer").data([0]);
+      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOSM(context).what(_note)).call(uiNoteReport(context).note(_note));
+      var osm = services.osm;
+      if (osm) {
+        osm.on("change.note-save", function() {
+          selection2.call(noteEditor);
         });
       }
-      var boxes = selection2.selectAll("." + which).data(gj);
-      boxes.exit().remove();
-      boxes.enter().append("path").attr("class", classes).merge(boxes).attr("d", path_default());
     }
-    function drawLabels(selection2, graph, entities, filter2, dimensions, fullRedraw) {
-      var wireframe = context.surface().classed("fill-wireframe");
-      var zoom = geoScaleToZoom(projection2.scale());
-      var labelable = [];
-      var renderNodeAs = {};
-      var i2, j2, k, entity, geometry;
-      for (i2 = 0; i2 < labelStack.length; i2++) {
-        labelable.push([]);
-      }
-      if (fullRedraw) {
-        _rdrawn.clear();
-        _rskipped.clear();
-        _entitybboxes = {};
-      } else {
-        for (i2 = 0; i2 < entities.length; i2++) {
-          entity = entities[i2];
-          var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + "I"] || []);
-          for (j2 = 0; j2 < toRemove.length; j2++) {
-            _rdrawn.remove(toRemove[j2]);
-            _rskipped.remove(toRemove[j2]);
-          }
+    function noteSaveSection(selection2) {
+      var isSelected = _note && _note.id === context.selectedNoteID();
+      var noteSave = selection2.selectAll(".note-save").data(isSelected ? [_note] : [], function(d2) {
+        return d2.status + d2.id;
+      });
+      noteSave.exit().remove();
+      var noteSaveEnter = noteSave.enter().append("div").attr("class", "note-save save-section cf");
+      noteSaveEnter.append("h4").attr("class", ".note-save-header").text("").each(function() {
+        if (_note.isNew()) {
+          _t.append("note.newDescription")(select_default2(this));
+        } else {
+          _t.append("note.newComment")(select_default2(this));
         }
+      });
+      var commentTextarea = noteSaveEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("note.inputPlaceholder")).attr("maxlength", 1e3).property("value", function(d2) {
+        return d2.newComment;
+      }).call(utilNoAuto).on("keydown.note-input", keydown).on("input.note-input", changeInput).on("blur.note-input", changeInput);
+      if (!commentTextarea.empty() && _newNote) {
+        commentTextarea.node().focus();
       }
-      for (i2 = 0; i2 < entities.length; i2++) {
-        entity = entities[i2];
-        geometry = entity.geometry(graph);
-        if (geometry === "point" || geometry === "vertex" && isInterestingVertex(entity)) {
-          var hasDirections = entity.directions(graph, projection2).length;
-          var markerPadding;
-          if (!wireframe && geometry === "point" && !(zoom >= 18 && hasDirections)) {
-            renderNodeAs[entity.id] = "point";
-            markerPadding = 20;
+      noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons);
+      function keydown(d3_event) {
+        if (!(d3_event.keyCode === 13 && // ↩ Return
+        d3_event.metaKey)) return;
+        var osm = services.osm;
+        if (!osm) return;
+        var hasAuth = osm.authenticated();
+        if (!hasAuth) return;
+        if (!_note.newComment) return;
+        d3_event.preventDefault();
+        select_default2(this).on("keydown.note-input", null);
+        window.setTimeout(function() {
+          if (_note.isNew()) {
+            noteSave.selectAll(".save-button").node().focus();
+            clickSave(_note);
           } else {
-            renderNodeAs[entity.id] = "vertex";
-            markerPadding = 0;
-          }
-          var coord2 = projection2(entity.loc);
-          var nodePadding = 10;
-          var bbox = {
-            minX: coord2[0] - nodePadding,
-            minY: coord2[1] - nodePadding - markerPadding,
-            maxX: coord2[0] + nodePadding,
-            maxY: coord2[1] + nodePadding
-          };
-          doInsert(bbox, entity.id + "P");
-        }
-        if (geometry === "vertex") {
-          geometry = "point";
-        }
-        var preset = geometry === "area" && _mainPresetIndex.match(entity, graph);
-        var icon2 = preset && !shouldSkipIcon(preset) && preset.icon;
-        if (!icon2 && !utilDisplayName(entity))
-          continue;
-        for (k = 0; k < labelStack.length; k++) {
-          var matchGeom = labelStack[k][0];
-          var matchKey = labelStack[k][1];
-          var matchVal = labelStack[k][2];
-          var hasVal = entity.tags[matchKey];
-          if (geometry === matchGeom && hasVal && (matchVal === "*" || matchVal === hasVal)) {
-            labelable[k].push(entity);
-            break;
+            noteSave.selectAll(".comment-button").node().focus();
+            clickComment(_note);
           }
-        }
+        }, 10);
       }
-      var positions = {
-        point: [],
-        line: [],
-        area: []
-      };
-      var labelled = {
-        point: [],
-        line: [],
-        area: []
-      };
-      for (k = 0; k < labelable.length; k++) {
-        var fontSize = labelStack[k][3];
-        for (i2 = 0; i2 < labelable[k].length; i2++) {
-          entity = labelable[k][i2];
-          geometry = entity.geometry(graph);
-          var getName = geometry === "line" ? utilDisplayNameForPath : utilDisplayName;
-          var name = getName(entity);
-          var width = name && textWidth(name, fontSize);
-          var p = null;
-          if (geometry === "point" || geometry === "vertex") {
-            if (wireframe)
-              continue;
-            var renderAs = renderNodeAs[entity.id];
-            if (renderAs === "vertex" && zoom < 17)
-              continue;
-            p = getPointLabel(entity, width, fontSize, renderAs);
-          } else if (geometry === "line") {
-            p = getLineLabel(entity, width, fontSize);
-          } else if (geometry === "area") {
-            p = getAreaLabel(entity, width, fontSize);
-          }
-          if (p) {
-            if (geometry === "vertex") {
-              geometry = "point";
-            }
-            p.classes = geometry + " tag-" + labelStack[k][1];
-            positions[geometry].push(p);
-            labelled[geometry].push(entity);
-          }
-        }
-      }
-      function isInterestingVertex(entity2) {
-        var selectedIDs = context.selectedIDs();
-        return entity2.hasInterestingTags() || entity2.isEndpoint(graph) || entity2.isConnected(graph) || selectedIDs.indexOf(entity2.id) !== -1 || graph.parentWays(entity2).some(function(parent) {
-          return selectedIDs.indexOf(parent.id) !== -1;
-        });
-      }
-      function getPointLabel(entity2, width2, height, geometry2) {
-        var y = geometry2 === "point" ? -12 : 0;
-        var pointOffsets = {
-          ltr: [15, y, "start"],
-          rtl: [-15, y, "end"]
-        };
-        var textDirection = _mainLocalizer.textDirection();
-        var coord3 = projection2(entity2.loc);
-        var textPadding = 2;
-        var offset = pointOffsets[textDirection];
-        var p2 = {
-          height,
-          width: width2,
-          x: coord3[0] + offset[0],
-          y: coord3[1] + offset[1],
-          textAnchor: offset[2]
-        };
-        var bbox2;
-        if (textDirection === "rtl") {
-          bbox2 = {
-            minX: p2.x - width2 - textPadding,
-            minY: p2.y - height / 2 - textPadding,
-            maxX: p2.x + textPadding,
-            maxY: p2.y + height / 2 + textPadding
-          };
-        } else {
-          bbox2 = {
-            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)) {
-          return p2;
-        }
-      }
-      function getLineLabel(entity2, width2, height) {
-        var viewport = geoExtent(context.projection.clipExtent()).polygon();
-        var points = graph.childNodes(entity2).map(function(node) {
-          return projection2(node.loc);
-        });
-        var length = geoPathLength(points);
-        if (length < width2 + 20)
-          return;
-        var lineOffsets = [
-          50,
-          45,
-          55,
-          40,
-          60,
-          35,
-          65,
-          30,
-          70,
-          25,
-          75,
-          20,
-          80,
-          15,
-          95,
-          10,
-          90,
-          5,
-          95
-        ];
-        var padding = 3;
-        for (var i3 = 0; i3 < lineOffsets.length; i3++) {
-          var offset = lineOffsets[i3];
-          var middle = offset / 100 * length;
-          var start2 = middle - width2 / 2;
-          if (start2 < 0 || start2 + width2 > length)
-            continue;
-          var sub = subpath(points, start2, start2 + width2);
-          if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
-            continue;
-          }
-          var isReverse = reverse(sub);
-          if (isReverse) {
-            sub = sub.reverse();
-          }
-          var bboxes = [];
-          var boxsize = (height + 2) / 2;
-          for (var j3 = 0; j3 < sub.length - 1; j3++) {
-            var a = sub[j3];
-            var b = sub[j3 + 1];
-            var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
-            for (var box = 0; box < num; box++) {
-              var p2 = geoVecInterp(a, b, box / num);
-              var x05 = p2[0] - boxsize - padding;
-              var y05 = p2[1] - boxsize - padding;
-              var x12 = p2[0] + boxsize + padding;
-              var y12 = p2[1] + boxsize + padding;
-              bboxes.push({
-                minX: Math.min(x05, x12),
-                minY: Math.min(y05, y12),
-                maxX: Math.max(x05, x12),
-                maxY: Math.max(y05, y12)
-              });
-            }
-          }
-          if (tryInsert(bboxes, entity2.id, false)) {
-            return {
-              "font-size": height + 2,
-              lineString: lineString2(sub),
-              startOffset: offset + "%"
-            };
-          }
-        }
-        function reverse(p3) {
-          var angle2 = Math.atan2(p3[1][1] - p3[0][1], p3[1][0] - p3[0][0]);
-          return !(p3[0][0] < p3[p3.length - 1][0] && angle2 < Math.PI / 2 && angle2 > -Math.PI / 2);
-        }
-        function lineString2(points2) {
-          return "M" + points2.join("L");
-        }
-        function subpath(points2, from, to) {
-          var sofar = 0;
-          var start3, end, i0, i1;
-          for (var i4 = 0; i4 < points2.length - 1; i4++) {
-            var a2 = points2[i4];
-            var b2 = points2[i4 + 1];
-            var current = geoVecLength(a2, b2);
-            var portion;
-            if (!start3 && sofar + current >= from) {
-              portion = (from - sofar) / current;
-              start3 = [
-                a2[0] + portion * (b2[0] - a2[0]),
-                a2[1] + portion * (b2[1] - a2[1])
-              ];
-              i0 = i4 + 1;
-            }
-            if (!end && sofar + current >= to) {
-              portion = (to - sofar) / current;
-              end = [
-                a2[0] + portion * (b2[0] - a2[0]),
-                a2[1] + portion * (b2[1] - a2[1])
-              ];
-              i1 = i4 + 1;
-            }
-            sofar += current;
-          }
-          var result = points2.slice(i0, i1);
-          result.unshift(start3);
-          result.push(end);
-          return result;
+      function changeInput() {
+        var input = select_default2(this);
+        var val = input.property("value").trim() || void 0;
+        _note = _note.update({ newComment: val });
+        var osm = services.osm;
+        if (osm) {
+          osm.replaceNote(_note);
         }
+        noteSave.call(noteSaveButtons);
       }
-      function getAreaLabel(entity2, width2, height) {
-        var centroid = path.centroid(entity2.asGeoJSON(graph));
-        var extent = entity2.extent(graph);
-        var areaWidth = projection2(extent[1])[0] - projection2(extent[0])[0];
-        if (isNaN(centroid[0]) || areaWidth < 20)
-          return;
-        var preset2 = _mainPresetIndex.match(entity2, context.graph());
-        var picon = preset2 && preset2.icon;
-        var iconSize = 17;
-        var padding = 2;
-        var p2 = {};
-        if (picon) {
-          if (addIcon()) {
-            addLabel(iconSize + padding);
-            return p2;
-          }
-        } else {
-          if (addLabel(0)) {
-            return p2;
-          }
-        }
-        function addIcon() {
-          var iconX = centroid[0] - iconSize / 2;
-          var iconY = centroid[1] - iconSize / 2;
-          var bbox2 = {
-            minX: iconX,
-            minY: iconY,
-            maxX: iconX + iconSize,
-            maxY: iconY + iconSize
-          };
-          if (tryInsert([bbox2], entity2.id + "I", true)) {
-            p2.transform = "translate(" + iconX + "," + iconY + ")";
-            return true;
-          }
-          return false;
-        }
-        function addLabel(yOffset) {
-          if (width2 && areaWidth >= width2 + 20) {
-            var labelX = centroid[0];
-            var labelY = centroid[1] + yOffset;
-            var bbox2 = {
-              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)) {
-              p2.x = labelX;
-              p2.y = labelY;
-              p2.textAnchor = "middle";
-              p2.height = height;
-              return true;
-            }
-          }
-          return false;
+    }
+    function userDetails(selection2) {
+      var detailSection = selection2.selectAll(".detail-section").data([0]);
+      detailSection = detailSection.enter().append("div").attr("class", "detail-section").merge(detailSection);
+      var osm = services.osm;
+      if (!osm) return;
+      var hasAuth = osm.authenticated();
+      var authWarning = detailSection.selectAll(".auth-warning").data(hasAuth ? [] : [0]);
+      authWarning.exit().transition().duration(200).style("opacity", 0).remove();
+      var authEnter = authWarning.enter().insert("div", ".tag-reference-body").attr("class", "field-warning auth-warning").style("opacity", 0);
+      authEnter.call(svgIcon("#iD-icon-alert", "inline"));
+      authEnter.append("span").call(_t.append("note.login"));
+      authEnter.append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.note-login", function(d3_event) {
+        d3_event.preventDefault();
+        osm.authenticate();
+      });
+      authEnter.transition().duration(200).style("opacity", 1);
+      var prose = detailSection.selectAll(".note-save-prose").data(hasAuth ? [0] : []);
+      prose.exit().remove();
+      prose = prose.enter().append("p").attr("class", "note-save-prose").call(_t.append("note.upload_explanation")).merge(prose);
+      osm.userDetails(function(err, user) {
+        if (err) return;
+        var userLink = select_default2(document.createElement("div"));
+        if (user.image_url) {
+          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
         }
+        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
+        prose.html(_t.html("note.upload_explanation_with_user", { user: { html: userLink.html() } }));
+      });
+    }
+    function noteSaveButtons(selection2) {
+      var osm = services.osm;
+      var hasAuth = osm && osm.authenticated();
+      var isSelected = _note && _note.id === context.selectedNoteID();
+      var buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_note] : [], function(d2) {
+        return d2.status + d2.id;
+      });
+      buttonSection.exit().remove();
+      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
+      if (_note.isNew()) {
+        buttonEnter.append("button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
+        buttonEnter.append("button").attr("class", "button save-button action").call(_t.append("note.save"));
+      } else {
+        buttonEnter.append("button").attr("class", "button status-button action");
+        buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("note.comment"));
       }
-      function doInsert(bbox2, id2) {
-        bbox2.id = id2;
-        var oldbox = _entitybboxes[id2];
-        if (oldbox) {
-          _rdrawn.remove(oldbox);
-        }
-        _entitybboxes[id2] = bbox2;
-        _rdrawn.insert(bbox2);
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
+      buttonSection.select(".save-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
+      buttonSection.select(".status-button").attr("disabled", hasAuth ? null : true).each(function(d2) {
+        var action = d2.status === "open" ? "close" : "open";
+        var andComment = d2.newComment ? "_comment" : "";
+        _t.addOrUpdate("note." + action + andComment)(select_default2(this));
+      }).on("click.status", clickStatus);
+      buttonSection.select(".comment-button").attr("disabled", isSaveDisabled).on("click.comment", clickComment);
+      function isSaveDisabled(d2) {
+        return hasAuth && d2.status === "open" && d2.newComment ? null : true;
       }
-      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]) {
-            skipped = true;
-            break;
-          }
-          if (_rdrawn.collides(bbox2)) {
-            skipped = true;
-            break;
-          }
-        }
-        _entitybboxes[id2] = bboxes;
-        if (skipped) {
-          if (saveSkipped) {
-            _rskipped.load(bboxes);
-          }
-        } else {
-          _rdrawn.load(bboxes);
-        }
-        return !skipped;
+    }
+    function clickCancel(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        osm.removeNote(d2);
       }
-      var layer = selection2.selectAll(".layer-osm.labels");
-      layer.selectAll(".labels-group").data(["halo", "label", "debug"]).enter().append("g").attr("class", function(d) {
-        return "labels-group " + d;
-      });
-      var halo = layer.selectAll(".labels-group.halo");
-      var label = layer.selectAll(".labels-group.label");
-      var debug2 = layer.selectAll(".labels-group.debug");
-      drawPointLabels(label, labelled.point, filter2, "pointlabel", positions.point);
-      drawPointLabels(halo, labelled.point, filter2, "pointlabel-halo", positions.point);
-      drawLinePaths(layer, labelled.line, filter2, "", positions.line);
-      drawLineLabels(label, labelled.line, filter2, "linelabel", positions.line);
-      drawLineLabels(halo, labelled.line, filter2, "linelabel-halo", positions.line);
-      drawAreaLabels(label, labelled.area, filter2, "arealabel", positions.area);
-      drawAreaLabels(halo, labelled.area, filter2, "arealabel-halo", positions.area);
-      drawAreaIcons(label, labelled.area, filter2, "areaicon", positions.area);
-      drawAreaIcons(halo, labelled.area, filter2, "areaicon-halo", positions.area);
-      drawCollisionBoxes(debug2, _rskipped, "debug-skipped");
-      drawCollisionBoxes(debug2, _rdrawn, "debug-drawn");
-      layer.call(filterLabels);
+      context.enter(modeBrowse(context));
+      dispatch14.call("change");
     }
-    function filterLabels(selection2) {
-      var drawLayer = selection2.selectAll(".layer-osm.labels");
-      var layers = drawLayer.selectAll(".labels-group.halo, .labels-group.label");
-      layers.selectAll(".nolabel").classed("nolabel", false);
-      var mouse = context.map().mouse();
-      var graph = context.graph();
-      var selectedIDs = context.selectedIDs();
-      var ids = [];
-      var pad2, bbox;
-      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) {
-          return entity2.id;
+    function clickSave(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        osm.postNoteCreate(d2, function(err, note) {
+          dispatch14.call("change", note);
         });
-        ids.push.apply(ids, nearMouse);
       }
-      for (var i2 = 0; i2 < selectedIDs.length; i2++) {
-        var entity = graph.hasEntity(selectedIDs[i2]);
-        if (entity && entity.type === "node") {
-          ids.push(selectedIDs[i2]);
-        }
+    }
+    function clickStatus(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        var setStatus = d2.status === "open" ? "closed" : "open";
+        osm.postNoteUpdate(d2, setStatus, function(err, note) {
+          dispatch14.call("change", note);
+        });
       }
-      layers.selectAll(utilEntitySelector(ids)).classed("nolabel", true);
-      var debug2 = selection2.selectAll(".labels-group.debug");
-      var gj = [];
-      if (context.getDebug("collision")) {
-        gj = bbox ? [{
-          type: "Polygon",
-          coordinates: [[
-            [bbox.minX, bbox.minY],
-            [bbox.maxX, bbox.minY],
-            [bbox.maxX, bbox.maxY],
-            [bbox.minX, bbox.maxY],
-            [bbox.minX, bbox.minY]
-          ]]
-        }] : [];
+    }
+    function clickComment(d3_event, d2) {
+      this.blur();
+      var osm = services.osm;
+      if (osm) {
+        osm.postNoteUpdate(d2, d2.status, function(err, note) {
+          dispatch14.call("change", note);
+        });
       }
-      var box = debug2.selectAll(".debug-mouse").data(gj);
-      box.exit().remove();
-      box.enter().append("path").attr("class", "debug debug-mouse yellow").merge(box).attr("d", path_default());
     }
-    var throttleFilterLabels = throttle_default(filterLabels, 100);
-    drawLabels.observe = function(selection2) {
-      var listener = function() {
-        throttleFilterLabels(selection2);
-      };
-      selection2.on("mousemove.hidelabels", listener);
-      context.on("enter.hidelabels", listener);
+    noteEditor.note = function(val) {
+      if (!arguments.length) return _note;
+      _note = val;
+      return noteEditor;
     };
-    drawLabels.off = function(selection2) {
-      throttleFilterLabels.cancel();
-      selection2.on("mousemove.hidelabels", null);
-      context.on("enter.hidelabels", null);
+    noteEditor.newNote = function(val) {
+      if (!arguments.length) return _newNote;
+      _newNote = val;
+      return noteEditor;
     };
-    return drawLabels;
+    return utilRebind(noteEditor, dispatch14, "on");
   }
 
-  // modules/svg/improveOSM.js
-  var _layerEnabled2 = false;
-  var _qaService2;
-  function svgImproveOSM(projection2, context, dispatch10) {
-    const throttledRedraw = throttle_default(() => dispatch10.call("change"), 1e3);
-    const minZoom3 = 12;
-    let touchLayer = select_default2(null);
-    let drawLayer = select_default2(null);
-    let layerVisible = false;
-    function markerPath(selection2, klass) {
-      selection2.attr("class", klass).attr("transform", "translate(-10, -28)").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
-    }
-    function getService() {
-      if (services.improveOSM && !_qaService2) {
-        _qaService2 = services.improveOSM;
-        _qaService2.on("loaded", throttledRedraw);
-      } else if (!services.improveOSM && _qaService2) {
-        _qaService2 = null;
-      }
-      return _qaService2;
-    }
-    function editOn() {
-      if (!layerVisible) {
-        layerVisible = true;
-        drawLayer.style("display", "block");
+  // modules/modes/select_note.js
+  function modeSelectNote(context, selectedNoteID) {
+    var mode = {
+      id: "select-note",
+      button: "browse"
+    };
+    var _keybinding = utilKeybinding("select-note");
+    var _noteEditor = uiNoteEditor(context).on("change", function() {
+      context.map().pan([0, 0]);
+      var note = checkSelectedID();
+      if (!note) return;
+      context.ui().sidebar.show(_noteEditor.note(note));
+    });
+    var _behaviors = [
+      behaviorBreathe(context),
+      behaviorHover(context),
+      behaviorSelect(context),
+      behaviorLasso(context),
+      modeDragNode(context).behavior,
+      modeDragNote(context).behavior
+    ];
+    var _newFeature = false;
+    function checkSelectedID() {
+      if (!services.osm) return;
+      var note = services.osm.getNote(selectedNoteID);
+      if (!note) {
+        context.enter(modeBrowse(context));
       }
+      return note;
     }
-    function editOff() {
-      if (layerVisible) {
-        layerVisible = false;
-        drawLayer.style("display", "none");
-        drawLayer.selectAll(".qaItem.improveOSM").remove();
-        touchLayer.selectAll(".qaItem.improveOSM").remove();
+    function selectNote(d3_event, drawn) {
+      if (!checkSelectedID()) return;
+      var selection2 = context.surface().selectAll(".layer-notes .note-" + selectedNoteID);
+      if (selection2.empty()) {
+        var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
+        if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
+          context.enter(modeBrowse(context));
+        }
+      } else {
+        selection2.classed("selected", true);
+        context.selectedNoteID(selectedNoteID);
       }
     }
-    function layerOn() {
-      editOn();
-      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", () => dispatch10.call("change"));
-    }
-    function layerOff() {
-      throttledRedraw.cancel();
-      drawLayer.interrupt();
-      touchLayer.selectAll(".qaItem.improveOSM").remove();
-      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", () => {
-        editOff();
-        dispatch10.call("change");
-      });
+    function esc() {
+      if (context.container().select(".combobox").size()) return;
+      context.enter(modeBrowse(context));
     }
-    function updateMarkers() {
-      if (!layerVisible || !_layerEnabled2)
-        return;
-      const service = getService();
-      const selectedID = context.selectedErrorID();
-      const data = service ? service.getItems(projection2) : [];
-      const getTransform = svgPointTransform(projection2);
-      const markers = drawLayer.selectAll(".qaItem.improveOSM").data(data, (d) => d.id);
-      markers.exit().remove();
-      const markersEnter = markers.enter().append("g").attr("class", (d) => `qaItem ${d.service} itemId-${d.id} itemType-${d.itemType}`);
-      markersEnter.append("polygon").call(markerPath, "shadow");
-      markersEnter.append("ellipse").attr("cx", 0).attr("cy", 0).attr("rx", 4.5).attr("ry", 2).attr("class", "stroke");
-      markersEnter.append("polygon").attr("fill", "currentColor").call(markerPath, "qaItem-fill");
-      markersEnter.append("use").attr("class", "icon-annotation").attr("transform", "translate(-6, -22)").attr("width", "12px").attr("height", "12px").attr("xlink:href", (d) => d.icon ? "#" + d.icon : "");
-      markers.merge(markersEnter).sort(sortY).classed("selected", (d) => d.id === selectedID).attr("transform", getTransform);
-      if (touchLayer.empty())
-        return;
-      const fillClass = context.getDebug("target") ? "pink " : "nocolor ";
-      const targets = touchLayer.selectAll(".qaItem.improveOSM").data(data, (d) => d.id);
-      targets.exit().remove();
-      targets.enter().append("rect").attr("width", "20px").attr("height", "30px").attr("x", "-10px").attr("y", "-28px").merge(targets).sort(sortY).attr("class", (d) => `qaItem ${d.service} target ${fillClass} itemId-${d.id}`).attr("transform", getTransform);
-      function sortY(a, b) {
-        return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
+    mode.zoomToSelected = function() {
+      if (!services.osm) return;
+      var note = services.osm.getNote(selectedNoteID);
+      if (note) {
+        context.map().centerZoomEase(note.loc, 20);
       }
+    };
+    mode.newFeature = function(val) {
+      if (!arguments.length) return _newFeature;
+      _newFeature = val;
+      return mode;
+    };
+    mode.enter = function() {
+      var note = checkSelectedID();
+      if (!note) return;
+      _behaviors.forEach(context.install);
+      _keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
+      select_default2(document).call(_keybinding);
+      selectNote();
+      var sidebar = context.ui().sidebar;
+      sidebar.show(_noteEditor.note(note).newNote(_newFeature));
+      sidebar.expand(sidebar.intersects(note.extent()));
+      context.map().on("drawn.select", selectNote);
+    };
+    mode.exit = function() {
+      _behaviors.forEach(context.uninstall);
+      select_default2(document).call(_keybinding.unbind);
+      context.surface().selectAll(".layer-notes .selected").classed("selected hover", false);
+      context.map().on("drawn.select", null);
+      context.ui().sidebar.hide();
+      context.selectedNoteID(null);
+    };
+    return mode;
+  }
+
+  // modules/modes/add_note.js
+  function modeAddNote(context) {
+    var mode = {
+      id: "add-note",
+      button: "note",
+      description: _t.append("modes.add_note.description"),
+      key: _t("modes.add_note.key")
+    };
+    var behavior = behaviorDraw(context).on("click", add).on("cancel", cancel).on("finish", cancel);
+    function add(loc) {
+      var osm = services.osm;
+      if (!osm) return;
+      var note = osmNote({ loc, status: "open", comments: [] });
+      osm.replaceNote(note);
+      context.map().pan([0, 0]);
+      context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
     }
-    function drawImproveOSM(selection2) {
-      const service = getService();
-      const surface = context.surface();
-      if (surface && !surface.empty()) {
-        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
-      }
-      drawLayer = selection2.selectAll(".layer-improveOSM").data(service ? [0] : []);
-      drawLayer.exit().remove();
-      drawLayer = drawLayer.enter().append("g").attr("class", "layer-improveOSM").style("display", _layerEnabled2 ? "block" : "none").merge(drawLayer);
-      if (_layerEnabled2) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          service.loadIssues(projection2);
-          updateMarkers();
-        } else {
-          editOff();
-        }
-      }
+    function cancel() {
+      context.enter(modeBrowse(context));
     }
-    drawImproveOSM.enabled = function(val) {
-      if (!arguments.length)
-        return _layerEnabled2;
-      _layerEnabled2 = val;
-      if (_layerEnabled2) {
-        layerOn();
-      } else {
-        layerOff();
-        if (context.selectedErrorID()) {
-          context.enter(modeBrowse(context));
-        }
-      }
-      dispatch10.call("change");
-      return this;
+    mode.enter = function() {
+      context.install(behavior);
+    };
+    mode.exit = function() {
+      context.uninstall(behavior);
     };
-    drawImproveOSM.supported = () => !!getService();
-    return drawImproveOSM;
+    return mode;
   }
 
-  // modules/svg/osmose.js
-  var _layerEnabled3 = false;
-  var _qaService3;
-  function svgOsmose(projection2, context, dispatch10) {
-    const throttledRedraw = throttle_default(() => dispatch10.call("change"), 1e3);
-    const minZoom3 = 12;
-    let touchLayer = select_default2(null);
-    let drawLayer = select_default2(null);
-    let layerVisible = false;
-    function markerPath(selection2, klass) {
-      selection2.attr("class", klass).attr("transform", "translate(-10, -28)").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
-    }
-    function getService() {
-      if (services.osmose && !_qaService3) {
-        _qaService3 = services.osmose;
-        _qaService3.on("loaded", throttledRedraw);
-      } else if (!services.osmose && _qaService3) {
-        _qaService3 = null;
+  // modules/util/jxon.js
+  var JXON = new function() {
+    var sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
+    function parseText(sValue) {
+      if (rIsNull.test(sValue)) {
+        return null;
       }
-      return _qaService3;
-    }
-    function editOn() {
-      if (!layerVisible) {
-        layerVisible = true;
-        drawLayer.style("display", "block");
+      if (rIsBool.test(sValue)) {
+        return sValue.toLowerCase() === "true";
       }
-    }
-    function editOff() {
-      if (layerVisible) {
-        layerVisible = false;
-        drawLayer.style("display", "none");
-        drawLayer.selectAll(".qaItem.osmose").remove();
-        touchLayer.selectAll(".qaItem.osmose").remove();
+      if (isFinite(sValue)) {
+        return parseFloat(sValue);
+      }
+      if (isFinite(Date.parse(sValue))) {
+        return new Date(sValue);
       }
+      return sValue;
     }
-    function layerOn() {
-      editOn();
-      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", () => dispatch10.call("change"));
+    function EmptyTree() {
     }
-    function layerOff() {
-      throttledRedraw.cancel();
-      drawLayer.interrupt();
-      touchLayer.selectAll(".qaItem.osmose").remove();
-      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", () => {
-        editOff();
-        dispatch10.call("change");
-      });
+    EmptyTree.prototype.toString = function() {
+      return "null";
+    };
+    EmptyTree.prototype.valueOf = function() {
+      return null;
+    };
+    function objectify(vValue) {
+      return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
     }
-    function updateMarkers() {
-      if (!layerVisible || !_layerEnabled3)
-        return;
-      const service = getService();
-      const selectedID = context.selectedErrorID();
-      const data = service ? service.getItems(projection2) : [];
-      const getTransform = svgPointTransform(projection2);
-      const markers = drawLayer.selectAll(".qaItem.osmose").data(data, (d) => d.id);
-      markers.exit().remove();
-      const markersEnter = markers.enter().append("g").attr("class", (d) => `qaItem ${d.service} itemId-${d.id} itemType-${d.itemType}`);
-      markersEnter.append("polygon").call(markerPath, "shadow");
-      markersEnter.append("ellipse").attr("cx", 0).attr("cy", 0).attr("rx", 4.5).attr("ry", 2).attr("class", "stroke");
-      markersEnter.append("polygon").attr("fill", (d) => service.getColor(d.item)).call(markerPath, "qaItem-fill");
-      markersEnter.append("use").attr("class", "icon-annotation").attr("transform", "translate(-6, -22)").attr("width", "12px").attr("height", "12px").attr("xlink:href", (d) => d.icon ? "#" + d.icon : "");
-      markers.merge(markersEnter).sort(sortY).classed("selected", (d) => d.id === selectedID).attr("transform", getTransform);
-      if (touchLayer.empty())
-        return;
-      const fillClass = context.getDebug("target") ? "pink" : "nocolor";
-      const targets = touchLayer.selectAll(".qaItem.osmose").data(data, (d) => d.id);
-      targets.exit().remove();
-      targets.enter().append("rect").attr("width", "20px").attr("height", "30px").attr("x", "-10px").attr("y", "-28px").merge(targets).sort(sortY).attr("class", (d) => `qaItem ${d.service} target ${fillClass} itemId-${d.id}`).attr("transform", getTransform);
-      function sortY(a, b) {
-        return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
+    function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
+      var nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(), bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
+      var sProp, vContent, nLength = 0, sCollectedTxt = "", vResult = bHighVerb ? {} : (
+        /* put here the default value for empty nodes: */
+        true
+      );
+      if (bChildren) {
+        for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
+          oNode = oParentNode.childNodes.item(nItem);
+          if (oNode.nodeType === 4) {
+            sCollectedTxt += oNode.nodeValue;
+          } else if (oNode.nodeType === 3) {
+            sCollectedTxt += oNode.nodeValue.trim();
+          } else if (oNode.nodeType === 1 && !oNode.prefix) {
+            aCache.push(oNode);
+          }
+        }
       }
-    }
-    function drawOsmose(selection2) {
-      const service = getService();
-      const surface = context.surface();
-      if (surface && !surface.empty()) {
-        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
+      var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
+      if (!bHighVerb && (bChildren || bAttributes)) {
+        vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
       }
-      drawLayer = selection2.selectAll(".layer-osmose").data(service ? [0] : []);
-      drawLayer.exit().remove();
-      drawLayer = drawLayer.enter().append("g").attr("class", "layer-osmose").style("display", _layerEnabled3 ? "block" : "none").merge(drawLayer);
-      if (_layerEnabled3) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          service.loadIssues(projection2);
-          updateMarkers();
+      for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
+        sProp = aCache[nElId].nodeName.toLowerCase();
+        vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
+        if (vResult.hasOwnProperty(sProp)) {
+          if (vResult[sProp].constructor !== Array) {
+            vResult[sProp] = [vResult[sProp]];
+          }
+          vResult[sProp].push(vContent);
         } else {
-          editOff();
+          vResult[sProp] = vContent;
+          nLength++;
         }
       }
-    }
-    drawOsmose.enabled = function(val) {
-      if (!arguments.length)
-        return _layerEnabled3;
-      _layerEnabled3 = val;
-      if (_layerEnabled3) {
-        getService().loadStrings().then(layerOn).catch((err) => {
-          console.log(err);
-        });
-      } else {
-        layerOff();
-        if (context.selectedErrorID()) {
-          context.enter(modeBrowse(context));
+      if (bAttributes) {
+        var nAttrLen = oParentNode.attributes.length, sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
+        for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
+          oAttrib = oParentNode.attributes.item(nAttrib);
+          oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
+        }
+        if (bNesteAttr) {
+          if (bFreeze) {
+            Object.freeze(oAttrParent);
+          }
+          vResult[sAttributesProp] = oAttrParent;
+          nLength -= nAttrLen - 1;
         }
       }
-      dispatch10.call("change");
-      return this;
-    };
-    drawOsmose.supported = () => !!getService();
-    return drawOsmose;
-  }
-
-  // modules/svg/streetside.js
-  function svgStreetside(projection2, context, dispatch10) {
-    var throttledRedraw = throttle_default(function() {
-      dispatch10.call("change");
-    }, 1e3);
-    var minZoom3 = 14;
-    var minMarkerZoom = 16;
-    var minViewfieldZoom = 18;
-    var layer = select_default2(null);
-    var _viewerYaw = 0;
-    var _selectedSequence = null;
-    var _streetside;
-    function init2() {
-      if (svgStreetside.initialized)
-        return;
-      svgStreetside.enabled = false;
-      svgStreetside.initialized = true;
-    }
-    function getService() {
-      if (services.streetside && !_streetside) {
-        _streetside = services.streetside;
-        _streetside.event.on("viewerChanged.svgStreetside", viewerChanged).on("loadedImages.svgStreetside", throttledRedraw);
-      } else if (!services.streetside && _streetside) {
-        _streetside = null;
+      if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
+        vResult[sValueProp] = vBuiltVal;
+      } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
+        vResult = vBuiltVal;
       }
-      return _streetside;
-    }
-    function showLayer() {
-      var service = getService();
-      if (!service)
-        return;
-      editOn();
-      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
-        dispatch10.call("change");
-      });
-    }
-    function hideLayer() {
-      throttledRedraw.cancel();
-      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
-    }
-    function editOn() {
-      layer.style("display", "block");
-    }
-    function editOff() {
-      layer.selectAll(".viewfield-group").remove();
-      layer.style("display", "none");
+      if (bFreeze && (bHighVerb || nLength > 0)) {
+        Object.freeze(vResult);
+      }
+      aCache.length = nLevelStart;
+      return vResult;
     }
-    function click(d3_event, d) {
-      var service = getService();
-      if (!service)
-        return;
-      if (d.sequenceKey !== _selectedSequence) {
-        _viewerYaw = 0;
+    function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
+      var vValue, oChild;
+      if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
+        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
+      } else if (oParentObj.constructor === Date) {
+        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
+      }
+      for (var sName in oParentObj) {
+        vValue = oParentObj[sName];
+        if (isFinite(sName) || vValue instanceof Function) {
+          continue;
+        }
+        if (sName === sValueProp) {
+          if (vValue !== null && vValue !== true) {
+            oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
+          }
+        } else if (sName === sAttributesProp) {
+          for (var sAttrib in vValue) {
+            oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
+          }
+        } else if (sName.charAt(0) === sAttrPref) {
+          oParentEl.setAttribute(sName.slice(1), vValue);
+        } else if (vValue.constructor === Array) {
+          for (var nItem = 0; nItem < vValue.length; nItem++) {
+            oChild = oXMLDoc.createElement(sName);
+            loadObjTree(oXMLDoc, oChild, vValue[nItem]);
+            oParentEl.appendChild(oChild);
+          }
+        } else {
+          oChild = oXMLDoc.createElement(sName);
+          if (vValue instanceof Object) {
+            loadObjTree(oXMLDoc, oChild, vValue);
+          } else if (vValue !== null && vValue !== true) {
+            oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
+          }
+          oParentEl.appendChild(oChild);
+        }
       }
-      _selectedSequence = d.sequenceKey;
-      service.ensureViewerLoaded(context).then(function() {
-        service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
-      });
-      context.map().centerEase(d.loc);
     }
-    function mouseover(d3_event, d) {
-      var service = getService();
-      if (service)
-        service.setStyles(context, d);
+    this.build = function(oXMLParent, nVerbosity, bFreeze, bNesteAttributes) {
+      var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : (
+        /* put here the default verbosity level: */
+        1
+      );
+      return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
+    };
+    this.unbuild = function(oObjTree) {
+      var oNewDoc = document.implementation.createDocument("", "", null);
+      loadObjTree(oNewDoc, oNewDoc, oObjTree);
+      return oNewDoc;
+    };
+    this.stringify = function(oObjTree) {
+      return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
+    };
+  }();
+
+  // modules/ui/conflicts.js
+  function uiConflicts(context) {
+    var dispatch14 = dispatch_default("cancel", "save");
+    var keybinding = utilKeybinding("conflicts");
+    var _origChanges;
+    var _conflictList;
+    var _shownConflictIndex;
+    function keybindingOn() {
+      select_default2(document).call(keybinding.on("\u238B", cancel, true));
     }
-    function mouseout() {
-      var service = getService();
-      if (service)
-        service.setStyles(context, null);
+    function keybindingOff() {
+      select_default2(document).call(keybinding.unbind);
     }
-    function transform2(d) {
-      var t = svgPointTransform(projection2)(d);
-      var rot = d.ca + _viewerYaw;
-      if (rot) {
-        t += " rotate(" + Math.floor(rot) + ",0,0)";
-      }
-      return t;
+    function tryAgain() {
+      keybindingOff();
+      dispatch14.call("save");
     }
-    function viewerChanged() {
-      var service = getService();
-      if (!service)
-        return;
-      var viewer = service.viewer();
-      if (!viewer)
-        return;
-      _viewerYaw = viewer.getYaw();
-      if (context.map().isTransformed())
-        return;
-      layer.selectAll(".viewfield-group.currentView").attr("transform", transform2);
+    function cancel() {
+      keybindingOff();
+      dispatch14.call("cancel");
     }
-    function filterBubbles(bubbles) {
-      var fromDate = context.photos().fromDate();
-      var toDate = context.photos().toDate();
-      var usernames = context.photos().usernames();
-      if (fromDate) {
-        var fromTimestamp = new Date(fromDate).getTime();
-        bubbles = bubbles.filter(function(bubble) {
-          return new Date(bubble.captured_at).getTime() >= fromTimestamp;
-        });
-      }
-      if (toDate) {
-        var toTimestamp = new Date(toDate).getTime();
-        bubbles = bubbles.filter(function(bubble) {
-          return new Date(bubble.captured_at).getTime() <= toTimestamp;
-        });
-      }
-      if (usernames) {
-        bubbles = bubbles.filter(function(bubble) {
-          return usernames.indexOf(bubble.captured_by) !== -1;
-        });
-      }
-      return bubbles;
+    function conflicts(selection2) {
+      keybindingOn();
+      var headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "fr").attr("title", _t("icons.close")).on("click", cancel).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("save.conflict.header"));
+      var bodyEnter = selection2.selectAll(".body").data([0]).enter().append("div").attr("class", "body fillL");
+      var conflictsHelpEnter = bodyEnter.append("div").attr("class", "conflicts-help").call(_t.append("save.conflict.help"));
+      var changeset = new osmChangeset();
+      delete changeset.id;
+      var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
+      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
+      var fileName = "changes.osc";
+      var linkEnter = conflictsHelpEnter.selectAll(".download-changes").append("a").attr("class", "download-changes");
+      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
+      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("save.conflict.download_changes"));
+      bodyEnter.append("div").attr("class", "conflict-container fillL3").call(showConflict, 0);
+      bodyEnter.append("div").attr("class", "conflicts-done").attr("opacity", 0).style("display", "none").call(_t.append("save.conflict.done"));
+      var buttonsEnter = bodyEnter.append("div").attr("class", "buttons col12 joined conflicts-buttons");
+      buttonsEnter.append("button").attr("disabled", _conflictList.length > 1).attr("class", "action conflicts-button col6").call(_t.append("save.title")).on("click.try_again", tryAgain);
+      buttonsEnter.append("button").attr("class", "secondary-action conflicts-button col6").call(_t.append("confirm.cancel")).on("click.cancel", cancel);
     }
-    function filterSequences(sequences) {
-      var fromDate = context.photos().fromDate();
-      var toDate = context.photos().toDate();
-      var usernames = context.photos().usernames();
-      if (fromDate) {
-        var fromTimestamp = new Date(fromDate).getTime();
-        sequences = sequences.filter(function(sequences2) {
-          return new Date(sequences2.properties.captured_at).getTime() >= fromTimestamp;
-        });
-      }
-      if (toDate) {
-        var toTimestamp = new Date(toDate).getTime();
-        sequences = sequences.filter(function(sequences2) {
-          return new Date(sequences2.properties.captured_at).getTime() <= toTimestamp;
-        });
-      }
-      if (usernames) {
-        sequences = sequences.filter(function(sequences2) {
-          return usernames.indexOf(sequences2.properties.captured_by) !== -1;
-        });
+    function showConflict(selection2, index) {
+      index = utilWrap(index, _conflictList.length);
+      _shownConflictIndex = index;
+      var parent = select_default2(selection2.node().parentNode);
+      if (index === _conflictList.length - 1) {
+        window.setTimeout(function() {
+          parent.select(".conflicts-button").attr("disabled", null);
+          parent.select(".conflicts-done").transition().attr("opacity", 1).style("display", "block");
+        }, 250);
       }
-      return sequences;
+      var conflict = selection2.selectAll(".conflict").data([_conflictList[index]]);
+      conflict.exit().remove();
+      var conflictEnter = conflict.enter().append("div").attr("class", "conflict");
+      conflictEnter.append("h4").attr("class", "conflict-count").call(_t.append("save.conflict.count", { num: index + 1, total: _conflictList.length }));
+      conflictEnter.append("a").attr("class", "conflict-description").attr("href", "#").text(function(d2) {
+        return d2.name;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        zoomToEntity(d2.id);
+      });
+      var details = conflictEnter.append("div").attr("class", "conflict-detail-container");
+      details.append("ul").attr("class", "conflict-detail-list").selectAll("li").data(function(d2) {
+        return d2.details || [];
+      }).enter().append("li").attr("class", "conflict-detail-item").html(function(d2) {
+        return d2;
+      });
+      details.append("div").attr("class", "conflict-choices").call(addChoices);
+      details.append("div").attr("class", "conflict-nav-buttons joined cf").selectAll("button").data(["previous", "next"]).enter().append("button").attr("class", "conflict-nav-button action col6").attr("disabled", function(d2, i3) {
+        return i3 === 0 && index === 0 || i3 === 1 && index === _conflictList.length - 1 || null;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        var container = parent.selectAll(".conflict-container");
+        var sign2 = d2 === "previous" ? -1 : 1;
+        container.selectAll(".conflict").remove();
+        container.call(showConflict, index + sign2);
+      }).each(function(d2) {
+        _t.append("save.conflict." + d2)(select_default2(this));
+      });
     }
-    function update() {
-      var viewer = context.container().select(".photoviewer");
-      var selected = viewer.empty() ? void 0 : viewer.datum();
-      var z = ~~context.map().zoom();
-      var showMarkers = z >= minMarkerZoom;
-      var showViewfields = z >= minViewfieldZoom;
-      var service = getService();
-      var sequences = [];
-      var bubbles = [];
-      if (context.photos().showsPanoramic()) {
-        sequences = service ? service.sequences(projection2) : [];
-        bubbles = service && showMarkers ? service.bubbles(projection2) : [];
-        sequences = filterSequences(sequences);
-        bubbles = filterBubbles(bubbles);
-      }
-      var traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d) {
-        return d.properties.key;
+    function addChoices(selection2) {
+      var choices = selection2.append("ul").attr("class", "layer-list").selectAll("li").data(function(d2) {
+        return d2.choices || [];
       });
-      traces.exit().remove();
-      traces = traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
-      var groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(bubbles, function(d) {
-        return d.key + (d.sequenceKey ? "v1" : "v0");
+      var choicesEnter = choices.enter().append("li").attr("class", "layer");
+      var labelEnter = choicesEnter.append("label");
+      labelEnter.append("input").attr("type", "radio").attr("name", function(d2) {
+        return d2.id;
+      }).on("change", function(d3_event, d2) {
+        var ul = this.parentNode.parentNode.parentNode;
+        ul.__data__.chosen = d2.id;
+        choose(d3_event, ul, d2);
       });
-      groups.exit().remove();
-      var groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
-      groupsEnter.append("g").attr("class", "viewfield-scale");
-      var markers = groups.merge(groupsEnter).sort(function(a, b) {
-        return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
-      }).attr("transform", transform2).select(".viewfield-scale");
-      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
-      var viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
-      viewfields.exit().remove();
-      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
-      function viewfieldPath() {
-        var d = this.parentNode.__data__;
-        if (d.pano) {
-          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
-        } else {
-          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+      labelEnter.append("span").text(function(d2) {
+        return d2.text;
+      });
+      choicesEnter.merge(choices).each(function(d2) {
+        var ul = this.parentNode;
+        if (ul.__data__.chosen === d2.id) {
+          choose(null, ul, d2);
         }
-      }
+      });
     }
-    function drawImages(selection2) {
-      var enabled = svgStreetside.enabled;
-      var service = getService();
-      layer = selection2.selectAll(".layer-streetside-images").data(service ? [0] : []);
-      layer.exit().remove();
-      var layerEnter = layer.enter().append("g").attr("class", "layer-streetside-images").style("display", enabled ? "block" : "none");
-      layerEnter.append("g").attr("class", "sequences");
-      layerEnter.append("g").attr("class", "markers");
-      layer = layerEnter.merge(layer);
-      if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          update();
-          service.loadBubbles(projection2);
+    function choose(d3_event, ul, datum2) {
+      if (d3_event) d3_event.preventDefault();
+      select_default2(ul).selectAll("li").classed("active", function(d2) {
+        return d2 === datum2;
+      }).selectAll("input").property("checked", function(d2) {
+        return d2 === datum2;
+      });
+      var extent = geoExtent();
+      var entity;
+      entity = context.graph().hasEntity(datum2.id);
+      if (entity) extent._extend(entity.extent(context.graph()));
+      datum2.action();
+      entity = context.graph().hasEntity(datum2.id);
+      if (entity) extent._extend(entity.extent(context.graph()));
+      zoomToEntity(datum2.id, extent);
+    }
+    function zoomToEntity(id2, extent) {
+      context.surface().selectAll(".hover").classed("hover", false);
+      var entity = context.graph().hasEntity(id2);
+      if (entity) {
+        if (extent) {
+          context.map().trimmedExtent(extent);
         } else {
-          editOff();
+          context.map().zoomToEase(entity);
         }
+        context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
       }
     }
-    drawImages.enabled = function(_) {
-      if (!arguments.length)
-        return svgStreetside.enabled;
-      svgStreetside.enabled = _;
-      if (svgStreetside.enabled) {
-        showLayer();
-        context.photos().on("change.streetside", update);
-      } else {
-        hideLayer();
-        context.photos().on("change.streetside", null);
+    conflicts.conflictList = function(_2) {
+      if (!arguments.length) return _conflictList;
+      _conflictList = _2;
+      return conflicts;
+    };
+    conflicts.origChanges = function(_2) {
+      if (!arguments.length) return _origChanges;
+      _origChanges = _2;
+      return conflicts;
+    };
+    conflicts.shownEntityIds = function() {
+      if (_conflictList && typeof _shownConflictIndex === "number") {
+        return [_conflictList[_shownConflictIndex].id];
       }
-      dispatch10.call("change");
-      return this;
+      return [];
     };
-    drawImages.supported = function() {
-      return !!getService();
+    return utilRebind(conflicts, dispatch14, "on");
+  }
+
+  // modules/ui/confirm.js
+  function uiConfirm(selection2) {
+    var modalSelection = uiModal(selection2);
+    modalSelection.select(".modal").classed("modal-alert", true);
+    var section = modalSelection.select(".content");
+    section.append("div").attr("class", "modal-section header");
+    section.append("div").attr("class", "modal-section message-text");
+    var buttons = section.append("div").attr("class", "modal-section buttons cf");
+    modalSelection.okButton = function() {
+      buttons.append("button").attr("class", "button ok-button action").on("click.confirm", function() {
+        modalSelection.remove();
+      }).call(_t.append("confirm.okay")).node().focus();
+      return modalSelection;
     };
-    init2();
-    return drawImages;
+    return modalSelection;
   }
 
-  // modules/svg/mapillary_images.js
-  function svgMapillaryImages(projection2, context, dispatch10) {
-    const throttledRedraw = throttle_default(function() {
-      dispatch10.call("change");
-    }, 1e3);
-    const minZoom3 = 12;
-    const minMarkerZoom = 16;
-    const minViewfieldZoom = 18;
-    let layer = select_default2(null);
-    let _mapillary;
-    function init2() {
-      if (svgMapillaryImages.initialized)
-        return;
-      svgMapillaryImages.enabled = false;
-      svgMapillaryImages.initialized = true;
-    }
-    function getService() {
-      if (services.mapillary && !_mapillary) {
-        _mapillary = services.mapillary;
-        _mapillary.event.on("loadedImages", throttledRedraw);
-      } else if (!services.mapillary && _mapillary) {
-        _mapillary = null;
+  // modules/ui/commit.js
+  var import_fast_deep_equal10 = __toESM(require_fast_deep_equal());
+
+  // modules/ui/popover.js
+  var _popoverID = 0;
+  function uiPopover(klass) {
+    var _id = _popoverID++;
+    var _anchorSelection = select_default2(null);
+    var popover = function(selection2) {
+      _anchorSelection = selection2;
+      selection2.each(setup);
+    };
+    var _animation = utilFunctor(false);
+    var _placement = utilFunctor("top");
+    var _alignment = utilFunctor("center");
+    var _scrollContainer = utilFunctor(select_default2(null));
+    var _content;
+    var _displayType = utilFunctor("");
+    var _hasArrow = utilFunctor(true);
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    popover.displayType = function(val) {
+      if (arguments.length) {
+        _displayType = utilFunctor(val);
+        return popover;
+      } else {
+        return _displayType;
       }
-      return _mapillary;
-    }
-    function showLayer() {
-      const service = getService();
-      if (!service)
-        return;
-      editOn();
-      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
-        dispatch10.call("change");
-      });
-    }
-    function hideLayer() {
-      throttledRedraw.cancel();
-      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
-    }
-    function editOn() {
-      layer.style("display", "block");
-    }
-    function editOff() {
-      layer.selectAll(".viewfield-group").remove();
-      layer.style("display", "none");
-    }
-    function click(d3_event, image) {
-      const service = getService();
-      if (!service)
-        return;
-      service.ensureViewerLoaded(context).then(function() {
-        service.selectImage(context, image.id).showViewer(context);
-      });
-      context.map().centerEase(image.loc);
-    }
-    function mouseover(d3_event, image) {
-      const service = getService();
-      if (service)
-        service.setStyles(context, image);
-    }
-    function mouseout() {
-      const service = getService();
-      if (service)
-        service.setStyles(context, null);
-    }
-    function transform2(d) {
-      let t = svgPointTransform(projection2)(d);
-      if (d.ca) {
-        t += " rotate(" + Math.floor(d.ca) + ",0,0)";
+    };
+    popover.hasArrow = function(val) {
+      if (arguments.length) {
+        _hasArrow = utilFunctor(val);
+        return popover;
+      } else {
+        return _hasArrow;
       }
-      return t;
-    }
-    function filterImages(images) {
-      const showsPano = context.photos().showsPanoramic();
-      const showsFlat = context.photos().showsFlat();
-      const fromDate = context.photos().fromDate();
-      const toDate = context.photos().toDate();
-      if (!showsPano || !showsFlat) {
-        images = images.filter(function(image) {
-          if (image.is_pano)
-            return showsPano;
-          return showsFlat;
-        });
-      }
-      if (fromDate) {
-        images = images.filter(function(image) {
-          return new Date(image.captured_at).getTime() >= new Date(fromDate).getTime();
-        });
-      }
-      if (toDate) {
-        images = images.filter(function(image) {
-          return new Date(image.captured_at).getTime() <= new Date(toDate).getTime();
-        });
-      }
-      return images;
-    }
-    function filterSequences(sequences) {
-      const showsPano = context.photos().showsPanoramic();
-      const showsFlat = context.photos().showsFlat();
-      const fromDate = context.photos().fromDate();
-      const toDate = context.photos().toDate();
-      if (!showsPano || !showsFlat) {
-        sequences = sequences.filter(function(sequence) {
-          if (sequence.properties.hasOwnProperty("is_pano")) {
-            if (sequence.properties.is_pano)
-              return showsPano;
-            return showsFlat;
-          }
-          return false;
-        });
-      }
-      if (fromDate) {
-        sequences = sequences.filter(function(sequence) {
-          return new Date(sequence.properties.captured_at).getTime() >= new Date(fromDate).getTime().toString();
-        });
-      }
-      if (toDate) {
-        sequences = sequences.filter(function(sequence) {
-          return new Date(sequence.properties.captured_at).getTime() <= new Date(toDate).getTime().toString();
-        });
+    };
+    popover.placement = function(val) {
+      if (arguments.length) {
+        _placement = utilFunctor(val);
+        return popover;
+      } else {
+        return _placement;
       }
-      return sequences;
-    }
-    function update() {
-      const z = ~~context.map().zoom();
-      const showMarkers = z >= minMarkerZoom;
-      const showViewfields = z >= minViewfieldZoom;
-      const service = getService();
-      let sequences = service ? service.sequences(projection2) : [];
-      let images = service && showMarkers ? service.images(projection2) : [];
-      images = filterImages(images);
-      sequences = filterSequences(sequences, service);
-      service.filterViewer(context);
-      let traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d) {
-        return d.properties.id;
-      });
-      traces.exit().remove();
-      traces = traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
-      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, function(d) {
-        return d.id;
-      });
-      groups.exit().remove();
-      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
-      groupsEnter.append("g").attr("class", "viewfield-scale");
-      const markers = groups.merge(groupsEnter).sort(function(a, b) {
-        return b.loc[1] - a.loc[1];
-      }).attr("transform", transform2).select(".viewfield-scale");
-      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
-      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
-      viewfields.exit().remove();
-      viewfields.enter().insert("path", "circle").attr("class", "viewfield").classed("pano", function() {
-        return this.parentNode.__data__.is_pano;
-      }).attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
-      function viewfieldPath() {
-        if (this.parentNode.__data__.is_pano) {
-          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
-        } else {
-          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
-        }
+    };
+    popover.alignment = function(val) {
+      if (arguments.length) {
+        _alignment = utilFunctor(val);
+        return popover;
+      } else {
+        return _alignment;
       }
-    }
-    function drawImages(selection2) {
-      const enabled = svgMapillaryImages.enabled;
-      const service = getService();
-      layer = selection2.selectAll(".layer-mapillary").data(service ? [0] : []);
-      layer.exit().remove();
-      const layerEnter = layer.enter().append("g").attr("class", "layer-mapillary").style("display", enabled ? "block" : "none");
-      layerEnter.append("g").attr("class", "sequences");
-      layerEnter.append("g").attr("class", "markers");
-      layer = layerEnter.merge(layer);
-      if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          update();
-          service.loadImages(projection2);
-        } else {
-          editOff();
-        }
+    };
+    popover.scrollContainer = function(val) {
+      if (arguments.length) {
+        _scrollContainer = utilFunctor(val);
+        return popover;
+      } else {
+        return _scrollContainer;
       }
-    }
-    drawImages.enabled = function(_) {
-      if (!arguments.length)
-        return svgMapillaryImages.enabled;
-      svgMapillaryImages.enabled = _;
-      if (svgMapillaryImages.enabled) {
-        showLayer();
-        context.photos().on("change.mapillary_images", update);
+    };
+    popover.content = function(val) {
+      if (arguments.length) {
+        _content = val;
+        return popover;
       } else {
-        hideLayer();
-        context.photos().on("change.mapillary_images", null);
+        return _content;
       }
-      dispatch10.call("change");
-      return this;
     };
-    drawImages.supported = function() {
-      return !!getService();
+    popover.isShown = function() {
+      var popoverSelection = _anchorSelection.select(".popover-" + _id);
+      return !popoverSelection.empty() && popoverSelection.classed("in");
     };
-    init2();
-    return drawImages;
-  }
-
-  // modules/svg/mapillary_position.js
-  function svgMapillaryPosition(projection2, context) {
-    const throttledRedraw = throttle_default(function() {
-      update();
-    }, 1e3);
-    const minZoom3 = 12;
-    const minViewfieldZoom = 18;
-    let layer = select_default2(null);
-    let _mapillary;
-    let viewerCompassAngle;
-    function init2() {
-      if (svgMapillaryPosition.initialized)
-        return;
-      svgMapillaryPosition.initialized = true;
-    }
-    function getService() {
-      if (services.mapillary && !_mapillary) {
-        _mapillary = services.mapillary;
-        _mapillary.event.on("imageChanged", throttledRedraw);
-        _mapillary.event.on("bearingChanged", function(e) {
-          viewerCompassAngle = e.bearing;
-          if (context.map().isTransformed())
-            return;
-          layer.selectAll(".viewfield-group.currentView").filter(function(d) {
-            return d.is_pano;
-          }).attr("transform", transform2);
+    popover.show = function() {
+      _anchorSelection.each(show);
+    };
+    popover.updateContent = function() {
+      _anchorSelection.each(updateContent);
+    };
+    popover.hide = function() {
+      _anchorSelection.each(hide);
+    };
+    popover.toggle = function() {
+      _anchorSelection.each(toggle);
+    };
+    popover.destroy = function(selection2, selector) {
+      selector = selector || ".popover-" + _id;
+      selection2.on(_pointerPrefix + "enter.popover", null).on(_pointerPrefix + "leave.popover", null).on(_pointerPrefix + "up.popover", null).on(_pointerPrefix + "down.popover", null).on("click.popover", null).attr("title", function() {
+        return this.getAttribute("data-original-title") || this.getAttribute("title");
+      }).attr("data-original-title", null).selectAll(selector).remove();
+    };
+    popover.destroyAny = function(selection2) {
+      selection2.call(popover.destroy, ".popover");
+    };
+    function setup() {
+      var anchor = select_default2(this);
+      var animate = _animation.apply(this, arguments);
+      var popoverSelection = anchor.selectAll(".popover-" + _id).data([0]);
+      var enter = popoverSelection.enter().append("div").attr("class", "popover popover-" + _id + " " + (klass ? klass : "")).classed("arrowed", _hasArrow.apply(this, arguments));
+      enter.append("div").attr("class", "popover-arrow");
+      enter.append("div").attr("class", "popover-inner");
+      popoverSelection = enter.merge(popoverSelection);
+      if (animate) {
+        popoverSelection.classed("fade", true);
+      }
+      var display = _displayType.apply(this, arguments);
+      if (display === "hover") {
+        var _lastNonMouseEnterTime;
+        anchor.on(_pointerPrefix + "enter.popover", function(d3_event) {
+          if (d3_event.pointerType) {
+            if (d3_event.pointerType !== "mouse") {
+              _lastNonMouseEnterTime = d3_event.timeStamp;
+              return;
+            } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
+              return;
+            }
+          }
+          if (d3_event.buttons !== 0) return;
+          show.apply(this, arguments);
+        }).on(_pointerPrefix + "leave.popover", function() {
+          hide.apply(this, arguments);
+        }).on("focus.popover", function() {
+          show.apply(this, arguments);
+        }).on("blur.popover", function() {
+          hide.apply(this, arguments);
+        });
+      } else if (display === "clickFocus") {
+        anchor.on(_pointerPrefix + "down.popover", function(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+        }).on(_pointerPrefix + "up.popover", function(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+        }).on("click.popover", toggle);
+        popoverSelection.attr("tabindex", 0).on("blur.popover", function() {
+          anchor.each(function() {
+            hide.apply(this, arguments);
+          });
         });
-      } else if (!services.mapillary && _mapillary) {
-        _mapillary = null;
       }
-      return _mapillary;
-    }
-    function editOn() {
-      layer.style("display", "block");
-    }
-    function editOff() {
-      layer.selectAll(".viewfield-group").remove();
-      layer.style("display", "none");
     }
-    function transform2(d) {
-      let t = svgPointTransform(projection2)(d);
-      if (d.is_pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
-        t += " rotate(" + Math.floor(viewerCompassAngle) + ",0,0)";
-      } else if (d.ca) {
-        t += " rotate(" + Math.floor(d.ca) + ",0,0)";
+    function show() {
+      var anchor = select_default2(this);
+      var popoverSelection = anchor.selectAll(".popover-" + _id);
+      if (popoverSelection.empty()) {
+        anchor.call(popover.destroy);
+        anchor.each(setup);
+        popoverSelection = anchor.selectAll(".popover-" + _id);
       }
-      return t;
-    }
-    function update() {
-      const z = ~~context.map().zoom();
-      const showViewfields = z >= minViewfieldZoom;
-      const service = getService();
-      const image = service && service.getActiveImage();
-      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(image ? [image] : [], function(d) {
-        return d.id;
-      });
-      groups.exit().remove();
-      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group currentView highlighted");
-      groupsEnter.append("g").attr("class", "viewfield-scale");
-      const markers = groups.merge(groupsEnter).attr("transform", transform2).select(".viewfield-scale");
-      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
-      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
-      viewfields.exit().remove();
-      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z");
-    }
-    function drawImages(selection2) {
-      const service = getService();
-      layer = selection2.selectAll(".layer-mapillary-position").data(service ? [0] : []);
-      layer.exit().remove();
-      const layerEnter = layer.enter().append("g").attr("class", "layer-mapillary-position");
-      layerEnter.append("g").attr("class", "markers");
-      layer = layerEnter.merge(layer);
-      if (service && ~~context.map().zoom() >= minZoom3) {
-        editOn();
-        update();
-      } else {
-        editOff();
+      popoverSelection.classed("in", true);
+      var displayType = _displayType.apply(this, arguments);
+      if (displayType === "clickFocus") {
+        anchor.classed("active", true);
+        popoverSelection.node().focus();
       }
+      anchor.each(updateContent);
     }
-    drawImages.enabled = function() {
-      update();
-      return this;
-    };
-    drawImages.supported = function() {
-      return !!getService();
-    };
-    init2();
-    return drawImages;
-  }
-
-  // modules/svg/mapillary_signs.js
-  function svgMapillarySigns(projection2, context, dispatch10) {
-    const throttledRedraw = throttle_default(function() {
-      dispatch10.call("change");
-    }, 1e3);
-    const minZoom3 = 12;
-    let layer = select_default2(null);
-    let _mapillary;
-    function init2() {
-      if (svgMapillarySigns.initialized)
-        return;
-      svgMapillarySigns.enabled = false;
-      svgMapillarySigns.initialized = true;
-    }
-    function getService() {
-      if (services.mapillary && !_mapillary) {
-        _mapillary = services.mapillary;
-        _mapillary.event.on("loadedSigns", throttledRedraw);
-      } else if (!services.mapillary && _mapillary) {
-        _mapillary = null;
+    function updateContent() {
+      var anchor = select_default2(this);
+      if (_content) {
+        anchor.selectAll(".popover-" + _id + " > .popover-inner").call(_content.apply(this, arguments));
       }
-      return _mapillary;
-    }
-    function showLayer() {
-      const service = getService();
-      if (!service)
-        return;
-      service.loadSignResources(context);
-      editOn();
-    }
-    function hideLayer() {
-      throttledRedraw.cancel();
-      editOff();
-    }
-    function editOn() {
-      layer.style("display", "block");
-    }
-    function editOff() {
-      layer.selectAll(".icon-sign").remove();
-      layer.style("display", "none");
+      updatePosition.apply(this, arguments);
+      updatePosition.apply(this, arguments);
+      updatePosition.apply(this, arguments);
     }
-    function click(d3_event, d) {
-      const service = getService();
-      if (!service)
-        return;
-      context.map().centerEase(d.loc);
-      const selectedImageId = service.getActiveImage() && service.getActiveImage().id;
-      service.getDetections(d.id).then((detections) => {
-        if (detections.length) {
-          const imageId = detections[0].image.id;
-          if (imageId === selectedImageId) {
-            service.highlightDetection(detections[0]).selectImage(context, imageId);
-          } else {
-            service.ensureViewerLoaded(context).then(function() {
-              service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
-            });
+    function updatePosition() {
+      var anchor = select_default2(this);
+      var popoverSelection = anchor.selectAll(".popover-" + _id);
+      var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
+      var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
+      var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
+      var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
+      var placement = _placement.apply(this, arguments);
+      popoverSelection.classed("left", false).classed("right", false).classed("top", false).classed("bottom", false).classed(placement, true);
+      var alignment = _alignment.apply(this, arguments);
+      var alignFactor = 0.5;
+      if (alignment === "leading") {
+        alignFactor = 0;
+      } else if (alignment === "trailing") {
+        alignFactor = 1;
+      }
+      var anchorFrame = getFrame(anchor.node());
+      var popoverFrame = getFrame(popoverSelection.node());
+      var position;
+      switch (placement) {
+        case "top":
+          position = {
+            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
+            y: anchorFrame.y - popoverFrame.h
+          };
+          break;
+        case "bottom":
+          position = {
+            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
+            y: anchorFrame.y + anchorFrame.h
+          };
+          break;
+        case "left":
+          position = {
+            x: anchorFrame.x - popoverFrame.w,
+            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
+          };
+          break;
+        case "right":
+          position = {
+            x: anchorFrame.x + anchorFrame.w,
+            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
+          };
+          break;
+      }
+      if (position) {
+        if (scrollNode && (placement === "top" || placement === "bottom")) {
+          var initialPosX = position.x;
+          if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
+            position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
+          } else if (position.x < 10) {
+            position.x = 10;
           }
+          var arrow = anchor.selectAll(".popover-" + _id + " > .popover-arrow");
+          var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
+          arrow.style("left", ~~arrowPosX + "px");
         }
-      });
-    }
-    function filterData(detectedFeatures) {
-      var fromDate = context.photos().fromDate();
-      var toDate = context.photos().toDate();
-      if (fromDate) {
-        var fromTimestamp = new Date(fromDate).getTime();
-        detectedFeatures = detectedFeatures.filter(function(feature3) {
-          return new Date(feature3.last_seen_at).getTime() >= fromTimestamp;
-        });
+        popoverSelection.style("left", ~~position.x + "px").style("top", ~~position.y + "px");
+      } else {
+        popoverSelection.style("left", null).style("top", null);
       }
-      if (toDate) {
-        var toTimestamp = new Date(toDate).getTime();
-        detectedFeatures = detectedFeatures.filter(function(feature3) {
-          return new Date(feature3.first_seen_at).getTime() <= toTimestamp;
-        });
+      function getFrame(node) {
+        var positionStyle = select_default2(node).style("position");
+        if (positionStyle === "absolute" || positionStyle === "static") {
+          return {
+            x: node.offsetLeft - scrollLeft,
+            y: node.offsetTop - scrollTop,
+            w: node.offsetWidth,
+            h: node.offsetHeight
+          };
+        } else {
+          return {
+            x: 0,
+            y: 0,
+            w: node.offsetWidth,
+            h: node.offsetHeight
+          };
+        }
       }
-      return detectedFeatures;
     }
-    function update() {
-      const service = getService();
-      let data = service ? service.signs(projection2) : [];
-      data = filterData(data);
-      const transform2 = svgPointTransform(projection2);
-      const signs = layer.selectAll(".icon-sign").data(data, function(d) {
-        return d.id;
-      });
-      signs.exit().remove();
-      const enter = signs.enter().append("g").attr("class", "icon-sign icon-detected").on("click", click);
-      enter.append("use").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px").attr("xlink:href", function(d) {
-        return "#" + d.value;
-      });
-      enter.append("rect").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px");
-      signs.merge(enter).attr("transform", transform2);
+    function hide() {
+      var anchor = select_default2(this);
+      if (_displayType.apply(this, arguments) === "clickFocus") {
+        anchor.classed("active", false);
+      }
+      anchor.selectAll(".popover-" + _id).classed("in", false);
     }
-    function drawSigns(selection2) {
-      const enabled = svgMapillarySigns.enabled;
-      const service = getService();
-      layer = selection2.selectAll(".layer-mapillary-signs").data(service ? [0] : []);
-      layer.exit().remove();
-      layer = layer.enter().append("g").attr("class", "layer-mapillary-signs layer-mapillary-detections").style("display", enabled ? "block" : "none").merge(layer);
-      if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          update();
-          service.loadSigns(projection2);
-          service.showSignDetections(true);
-        } else {
-          editOff();
-        }
-      } else if (service) {
-        service.showSignDetections(false);
+    function toggle() {
+      if (select_default2(this).select(".popover-" + _id).classed("in")) {
+        hide.apply(this, arguments);
+      } else {
+        show.apply(this, arguments);
       }
     }
-    drawSigns.enabled = function(_) {
-      if (!arguments.length)
-        return svgMapillarySigns.enabled;
-      svgMapillarySigns.enabled = _;
-      if (svgMapillarySigns.enabled) {
-        showLayer();
-        context.photos().on("change.mapillary_signs", update);
+    return popover;
+  }
+
+  // modules/ui/tooltip.js
+  function uiTooltip(klass) {
+    var tooltip = uiPopover((klass || "") + " tooltip").displayType("hover");
+    var _title = function() {
+      var title = this.getAttribute("data-original-title");
+      if (title) {
+        return title;
       } else {
-        hideLayer();
-        context.photos().on("change.mapillary_signs", null);
+        title = this.getAttribute("title");
+        this.removeAttribute("title");
+        this.setAttribute("data-original-title", title);
       }
-      dispatch10.call("change");
-      return this;
+      return title;
     };
-    drawSigns.supported = function() {
-      return !!getService();
+    var _heading = utilFunctor(null);
+    var _keys = utilFunctor(null);
+    tooltip.title = function(val) {
+      if (!arguments.length) return _title;
+      _title = utilFunctor(val);
+      return tooltip;
     };
-    init2();
-    return drawSigns;
+    tooltip.heading = function(val) {
+      if (!arguments.length) return _heading;
+      _heading = utilFunctor(val);
+      return tooltip;
+    };
+    tooltip.keys = function(val) {
+      if (!arguments.length) return _keys;
+      _keys = utilFunctor(val);
+      return tooltip;
+    };
+    tooltip.content(function() {
+      var heading2 = _heading.apply(this, arguments);
+      var text = _title.apply(this, arguments);
+      var keys2 = _keys.apply(this, arguments);
+      var headingCallback = typeof heading2 === "function" ? heading2 : (s2) => s2.text(heading2);
+      var textCallback = typeof text === "function" ? text : (s2) => s2.text(text);
+      return function(selection2) {
+        var headingSelect = selection2.selectAll(".tooltip-heading").data(heading2 ? [heading2] : []);
+        headingSelect.exit().remove();
+        headingSelect.enter().append("div").attr("class", "tooltip-heading").merge(headingSelect).text("").call(headingCallback);
+        var textSelect = selection2.selectAll(".tooltip-text").data(text ? [text] : []);
+        textSelect.exit().remove();
+        textSelect.enter().append("div").attr("class", "tooltip-text").merge(textSelect).text("").call(textCallback);
+        var keyhintWrap = selection2.selectAll(".keyhint-wrap").data(keys2 && keys2.length ? [0] : []);
+        keyhintWrap.exit().remove();
+        var keyhintWrapEnter = keyhintWrap.enter().append("div").attr("class", "keyhint-wrap");
+        keyhintWrapEnter.append("span").call(_t.append("tooltip_keyhint"));
+        keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
+        keyhintWrap.selectAll("kbd.shortcut").data(keys2 && keys2.length ? keys2 : []).enter().append("kbd").attr("class", "shortcut").text(function(d2) {
+          return d2;
+        });
+      };
+    });
+    return tooltip;
   }
 
-  // modules/svg/mapillary_map_features.js
-  function svgMapillaryMapFeatures(projection2, context, dispatch10) {
-    const throttledRedraw = throttle_default(function() {
-      dispatch10.call("change");
-    }, 1e3);
-    const minZoom3 = 12;
-    let layer = select_default2(null);
-    let _mapillary;
-    function init2() {
-      if (svgMapillaryMapFeatures.initialized)
-        return;
-      svgMapillaryMapFeatures.enabled = false;
-      svgMapillaryMapFeatures.initialized = true;
-    }
-    function getService() {
-      if (services.mapillary && !_mapillary) {
-        _mapillary = services.mapillary;
-        _mapillary.event.on("loadedMapFeatures", throttledRedraw);
-      } else if (!services.mapillary && _mapillary) {
-        _mapillary = null;
-      }
-      return _mapillary;
-    }
-    function showLayer() {
-      const service = getService();
-      if (!service)
-        return;
-      service.loadObjectResources(context);
-      editOn();
-    }
-    function hideLayer() {
-      throttledRedraw.cancel();
-      editOff();
-    }
-    function editOn() {
-      layer.style("display", "block");
-    }
-    function editOff() {
-      layer.selectAll(".icon-map-feature").remove();
-      layer.style("display", "none");
-    }
-    function click(d3_event, d) {
-      const service = getService();
-      if (!service)
-        return;
-      context.map().centerEase(d.loc);
-      const selectedImageId = service.getActiveImage() && service.getActiveImage().id;
-      service.getDetections(d.id).then((detections) => {
-        if (detections.length) {
-          const imageId = detections[0].image.id;
-          if (imageId === selectedImageId) {
-            service.highlightDetection(detections[0]).selectImage(context, imageId);
-          } else {
-            service.ensureViewerLoaded(context).then(function() {
-              service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
-            });
-          }
+  // modules/ui/combobox.js
+  var _comboHideTimerID;
+  function uiCombobox(context, klass) {
+    var dispatch14 = dispatch_default("accept", "cancel", "update");
+    var container = context.container();
+    var _suggestions = [];
+    var _data = [];
+    var _fetched = {};
+    var _selected = null;
+    var _canAutocomplete = true;
+    var _caseSensitive = false;
+    var _cancelFetch = false;
+    var _minItems = 2;
+    var _tDown = 0;
+    var _mouseEnterHandler, _mouseLeaveHandler;
+    var _fetcher = function(val, cb) {
+      cb(_data.filter(function(d2) {
+        var terms = d2.terms || [];
+        terms.push(d2.value);
+        if (d2.key) {
+          terms.push(d2.key);
         }
-      });
-    }
-    function filterData(detectedFeatures) {
-      const fromDate = context.photos().fromDate();
-      const toDate = context.photos().toDate();
-      if (fromDate) {
-        detectedFeatures = detectedFeatures.filter(function(feature3) {
-          return new Date(feature3.last_seen_at).getTime() >= new Date(fromDate).getTime();
+        return terms.some(function(term) {
+          return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
         });
-      }
-      if (toDate) {
-        detectedFeatures = detectedFeatures.filter(function(feature3) {
-          return new Date(feature3.first_seen_at).getTime() <= new Date(toDate).getTime();
+      }));
+    };
+    var combobox = function(input, attachTo) {
+      if (!input || input.empty()) return;
+      input.classed("combobox-input", true).on("focus.combo-input", focus).on("blur.combo-input", blur).on("keydown.combo-input", keydown).on("keyup.combo-input", keyup).on("input.combo-input", change).on("mousedown.combo-input", mousedown).each(function() {
+        var parent = this.parentNode;
+        var sibling = this.nextSibling;
+        select_default2(parent).selectAll(".combobox-caret").filter(function(d2) {
+          return d2 === input.node();
+        }).data([input.node()]).enter().insert("div", function() {
+          return sibling;
+        }).attr("class", "combobox-caret").on("mousedown.combo-caret", function(d3_event) {
+          d3_event.preventDefault();
+          input.node().focus();
+          mousedown(d3_event);
+        }).on("mouseup.combo-caret", function(d3_event) {
+          d3_event.preventDefault();
+          mouseup(d3_event);
         });
-      }
-      return detectedFeatures;
-    }
-    function update() {
-      const service = getService();
-      let data = service ? service.mapFeatures(projection2) : [];
-      data = filterData(data);
-      const transform2 = svgPointTransform(projection2);
-      const mapFeatures = layer.selectAll(".icon-map-feature").data(data, function(d) {
-        return d.id;
-      });
-      mapFeatures.exit().remove();
-      const enter = mapFeatures.enter().append("g").attr("class", "icon-map-feature icon-detected").on("click", click);
-      enter.append("title").text(function(d) {
-        var id2 = d.value.replace(/--/g, ".").replace(/-/g, "_");
-        return _t("mapillary_map_features." + id2);
       });
-      enter.append("use").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px").attr("xlink:href", function(d) {
-        if (d.value === "object--billboard") {
-          return "#object--sign--advertisement";
+      function mousedown(d3_event) {
+        if (d3_event.button !== 0) return;
+        if (input.classed("disabled")) return;
+        _tDown = +/* @__PURE__ */ new Date();
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        if (start2 !== end) {
+          var val = utilGetSetValue(input);
+          input.node().setSelectionRange(val.length, val.length);
+          return;
         }
-        return "#" + d.value;
-      });
-      enter.append("rect").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px");
-      mapFeatures.merge(enter).attr("transform", transform2);
-    }
-    function drawMapFeatures(selection2) {
-      const enabled = svgMapillaryMapFeatures.enabled;
-      const service = getService();
-      layer = selection2.selectAll(".layer-mapillary-map-features").data(service ? [0] : []);
-      layer.exit().remove();
-      layer = layer.enter().append("g").attr("class", "layer-mapillary-map-features layer-mapillary-detections").style("display", enabled ? "block" : "none").merge(layer);
-      if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          update();
-          service.loadMapFeatures(projection2);
-          service.showFeatureDetections(true);
+        input.on("mouseup.combo-input", mouseup);
+      }
+      function mouseup(d3_event) {
+        input.on("mouseup.combo-input", null);
+        if (d3_event.button !== 0) return;
+        if (input.classed("disabled")) return;
+        if (input.node() !== document.activeElement) return;
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        if (start2 !== end) return;
+        var combo = container.selectAll(".combobox");
+        if (combo.empty() || combo.datum() !== input.node()) {
+          var tOrig = _tDown;
+          window.setTimeout(function() {
+            if (tOrig !== _tDown) return;
+            fetchComboData("", function() {
+              show();
+              render();
+            });
+          }, 250);
         } else {
-          editOff();
+          hide();
         }
-      } else if (service) {
-        service.showFeatureDetections(false);
-      }
-    }
-    drawMapFeatures.enabled = function(_) {
-      if (!arguments.length)
-        return svgMapillaryMapFeatures.enabled;
-      svgMapillaryMapFeatures.enabled = _;
-      if (svgMapillaryMapFeatures.enabled) {
-        showLayer();
-        context.photos().on("change.mapillary_map_features", update);
-      } else {
-        hideLayer();
-        context.photos().on("change.mapillary_map_features", null);
       }
-      dispatch10.call("change");
-      return this;
-    };
-    drawMapFeatures.supported = function() {
-      return !!getService();
-    };
-    init2();
-    return drawMapFeatures;
-  }
-
-  // modules/svg/kartaview_images.js
-  function svgKartaviewImages(projection2, context, dispatch10) {
-    var throttledRedraw = throttle_default(function() {
-      dispatch10.call("change");
-    }, 1e3);
-    var minZoom3 = 12;
-    var minMarkerZoom = 16;
-    var minViewfieldZoom = 18;
-    var layer = select_default2(null);
-    var _kartaview;
-    function init2() {
-      if (svgKartaviewImages.initialized)
-        return;
-      svgKartaviewImages.enabled = false;
-      svgKartaviewImages.initialized = true;
-    }
-    function getService() {
-      if (services.kartaview && !_kartaview) {
-        _kartaview = services.kartaview;
-        _kartaview.event.on("loadedImages", throttledRedraw);
-      } else if (!services.kartaview && _kartaview) {
-        _kartaview = null;
+      function focus() {
+        fetchComboData("");
       }
-      return _kartaview;
-    }
-    function showLayer() {
-      var service = getService();
-      if (!service)
-        return;
-      editOn();
-      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
-        dispatch10.call("change");
-      });
-    }
-    function hideLayer() {
-      throttledRedraw.cancel();
-      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
-    }
-    function editOn() {
-      layer.style("display", "block");
-    }
-    function editOff() {
-      layer.selectAll(".viewfield-group").remove();
-      layer.style("display", "none");
-    }
-    function click(d3_event, d) {
-      var service = getService();
-      if (!service)
-        return;
-      service.ensureViewerLoaded(context).then(function() {
-        service.selectImage(context, d.key).showViewer(context);
-      });
-      context.map().centerEase(d.loc);
-    }
-    function mouseover(d3_event, d) {
-      var service = getService();
-      if (service)
-        service.setStyles(context, d);
-    }
-    function mouseout() {
-      var service = getService();
-      if (service)
-        service.setStyles(context, null);
-    }
-    function transform2(d) {
-      var t = svgPointTransform(projection2)(d);
-      if (d.ca) {
-        t += " rotate(" + Math.floor(d.ca) + ",0,0)";
+      function blur() {
+        _comboHideTimerID = window.setTimeout(hide, 75);
       }
-      return t;
-    }
-    function filterImages(images) {
-      var fromDate = context.photos().fromDate();
-      var toDate = context.photos().toDate();
-      var usernames = context.photos().usernames();
-      if (fromDate) {
-        var fromTimestamp = new Date(fromDate).getTime();
-        images = images.filter(function(item) {
-          return new Date(item.captured_at).getTime() >= fromTimestamp;
+      function show() {
+        hide();
+        container.insert("div", ":first-child").datum(input.node()).attr("class", "combobox" + (klass ? " combobox-" + klass : "")).style("position", "absolute").style("display", "block").style("left", "0px").on("mousedown.combo-container", function(d3_event) {
+          d3_event.preventDefault();
         });
+        container.on("scroll.combo-scroll", render, true);
       }
-      if (toDate) {
-        var toTimestamp = new Date(toDate).getTime();
-        images = images.filter(function(item) {
-          return new Date(item.captured_at).getTime() <= toTimestamp;
-        });
+      function hide() {
+        if (_comboHideTimerID) {
+          window.clearTimeout(_comboHideTimerID);
+          _comboHideTimerID = void 0;
+        }
+        container.selectAll(".combobox").remove();
+        container.on("scroll.combo-scroll", null);
       }
-      if (usernames) {
-        images = images.filter(function(item) {
-          return usernames.indexOf(item.captured_by) !== -1;
-        });
+      function keydown(d3_event) {
+        var shown = !container.selectAll(".combobox").empty();
+        var tagName = input.node() ? input.node().tagName.toLowerCase() : "";
+        switch (d3_event.keyCode) {
+          case 8:
+          // ⌫ Backspace
+          case 46:
+            d3_event.stopPropagation();
+            _selected = null;
+            render();
+            input.on("input.combo-input", function() {
+              var start2 = input.property("selectionStart");
+              input.node().setSelectionRange(start2, start2);
+              input.on("input.combo-input", change);
+              change(false);
+            });
+            break;
+          case 9:
+            accept(d3_event);
+            break;
+          case 13:
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            accept(d3_event);
+            break;
+          case 38:
+            if (tagName === "textarea" && !shown) return;
+            d3_event.preventDefault();
+            if (tagName === "input" && !shown) {
+              show();
+            }
+            nav(-1);
+            break;
+          case 40:
+            if (tagName === "textarea" && !shown) return;
+            d3_event.preventDefault();
+            if (tagName === "input" && !shown) {
+              show();
+            }
+            nav(1);
+            break;
+        }
       }
-      return images;
-    }
-    function filterSequences(sequences) {
-      var fromDate = context.photos().fromDate();
-      var toDate = context.photos().toDate();
-      var usernames = context.photos().usernames();
-      if (fromDate) {
-        var fromTimestamp = new Date(fromDate).getTime();
-        sequences = sequences.filter(function(image) {
-          return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
+      function keyup(d3_event) {
+        switch (d3_event.keyCode) {
+          case 27:
+            cancel();
+            break;
+        }
+      }
+      function change(doAutoComplete) {
+        if (doAutoComplete === void 0) doAutoComplete = true;
+        fetchComboData(value(), function(skipAutosuggest) {
+          _selected = null;
+          var val = input.property("value");
+          if (_suggestions.length) {
+            if (doAutoComplete && !skipAutosuggest && input.property("selectionEnd") === val.length) {
+              _selected = tryAutocomplete();
+            }
+            if (!_selected) {
+              _selected = val;
+            }
+          }
+          if (val.length) {
+            var combo = container.selectAll(".combobox");
+            if (combo.empty()) {
+              show();
+            }
+          } else {
+            hide();
+          }
+          render();
         });
       }
-      if (toDate) {
-        var toTimestamp = new Date(toDate).getTime();
-        sequences = sequences.filter(function(image) {
-          return new Date(image.properties.captured_at).getTime() <= toTimestamp;
+      function nav(dir) {
+        if (_suggestions.length) {
+          var index = -1;
+          for (var i3 = 0; i3 < _suggestions.length; i3++) {
+            if (_selected && _suggestions[i3].value === _selected) {
+              index = i3;
+              break;
+            }
+          }
+          index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
+          _selected = _suggestions[index].value;
+          utilGetSetValue(input, _selected);
+          dispatch14.call("update");
+        }
+        render();
+        ensureVisible();
+      }
+      function ensureVisible() {
+        var combo = container.selectAll(".combobox");
+        if (combo.empty()) return;
+        var containerRect = container.node().getBoundingClientRect();
+        var comboRect = combo.node().getBoundingClientRect();
+        if (comboRect.bottom > containerRect.bottom) {
+          var node = attachTo ? attachTo.node() : input.node();
+          node.scrollIntoView({ behavior: "instant", block: "center" });
+          render();
+        }
+        var selected = combo.selectAll(".combobox-option.selected").node();
+        if (selected) {
+          selected.scrollIntoView({ behavior: "smooth", block: "nearest" });
+        }
+      }
+      function value() {
+        var value2 = input.property("value");
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        if (start2 && end) {
+          value2 = value2.substring(0, start2);
+        }
+        return value2;
+      }
+      function fetchComboData(v2, cb) {
+        _cancelFetch = false;
+        _fetcher.call(input, v2, function(results, skipAutosuggest) {
+          if (_cancelFetch) return;
+          _suggestions = results;
+          results.forEach(function(d2) {
+            _fetched[d2.value] = d2;
+          });
+          if (cb) {
+            cb(skipAutosuggest);
+          }
         });
       }
-      if (usernames) {
-        sequences = sequences.filter(function(image) {
-          return usernames.indexOf(image.properties.captured_by) !== -1;
+      function tryAutocomplete() {
+        if (!_canAutocomplete) return;
+        var val = _caseSensitive ? value() : value().toLowerCase();
+        if (!val) return;
+        if (isFinite(val)) return;
+        const suggestionValues = [];
+        _suggestions.forEach((s2) => {
+          suggestionValues.push(s2.value);
+          if (s2.key && s2.key !== s2.value) {
+            suggestionValues.push(s2.key);
+          }
         });
+        var bestIndex = -1;
+        for (var i3 = 0; i3 < suggestionValues.length; i3++) {
+          var suggestion = suggestionValues[i3];
+          var compare2 = _caseSensitive ? suggestion : suggestion.toLowerCase();
+          if (compare2 === val) {
+            bestIndex = i3;
+            break;
+          } else if (bestIndex === -1 && compare2.indexOf(val) === 0) {
+            bestIndex = i3;
+          }
+        }
+        if (bestIndex !== -1) {
+          var bestVal = suggestionValues[bestIndex];
+          input.property("value", bestVal);
+          input.node().setSelectionRange(val.length, bestVal.length);
+          dispatch14.call("update");
+          return bestVal;
+        }
       }
-      return sequences;
-    }
-    function update() {
-      var viewer = context.container().select(".photoviewer");
-      var selected = viewer.empty() ? void 0 : viewer.datum();
-      var z = ~~context.map().zoom();
-      var showMarkers = z >= minMarkerZoom;
-      var showViewfields = z >= minViewfieldZoom;
-      var service = getService();
-      var sequences = [];
-      var images = [];
-      if (context.photos().showsFlat()) {
-        sequences = service ? service.sequences(projection2) : [];
-        images = service && showMarkers ? service.images(projection2) : [];
-        sequences = filterSequences(sequences);
-        images = filterImages(images);
+      function render() {
+        if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
+          hide();
+          return;
+        }
+        var shown = !container.selectAll(".combobox").empty();
+        if (!shown) return;
+        var combo = container.selectAll(".combobox");
+        var options2 = combo.selectAll(".combobox-option").data(_suggestions, function(d2) {
+          return d2.value;
+        });
+        options2.exit().remove();
+        options2.enter().append("a").attr("class", function(d2) {
+          return "combobox-option " + (d2.klass || "");
+        }).attr("title", function(d2) {
+          return d2.title;
+        }).each(function(d2) {
+          if (d2.display) {
+            d2.display(select_default2(this));
+          } else {
+            select_default2(this).text(d2.value);
+          }
+        }).on("mouseenter", _mouseEnterHandler).on("mouseleave", _mouseLeaveHandler).merge(options2).classed("selected", function(d2) {
+          return d2.value === _selected || d2.key === _selected;
+        }).on("click.combo-option", accept).order();
+        var node = attachTo ? attachTo.node() : input.node();
+        var containerRect = container.node().getBoundingClientRect();
+        var rect = node.getBoundingClientRect();
+        combo.style("left", rect.left + 5 - containerRect.left + "px").style("width", rect.width - 10 + "px").style("top", rect.height + rect.top - containerRect.top + "px");
       }
-      var traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d) {
-        return d.properties.key;
-      });
-      traces.exit().remove();
-      traces = traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
-      var groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, function(d) {
-        return d.key;
-      });
-      groups.exit().remove();
-      var groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
-      groupsEnter.append("g").attr("class", "viewfield-scale");
-      var markers = groups.merge(groupsEnter).sort(function(a, b) {
-        return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
-      }).attr("transform", transform2).select(".viewfield-scale");
-      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
-      var viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
-      viewfields.exit().remove();
-      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z");
-    }
-    function drawImages(selection2) {
-      var enabled = svgKartaviewImages.enabled, service = getService();
-      layer = selection2.selectAll(".layer-kartaview").data(service ? [0] : []);
-      layer.exit().remove();
-      var layerEnter = layer.enter().append("g").attr("class", "layer-kartaview").style("display", enabled ? "block" : "none");
-      layerEnter.append("g").attr("class", "sequences");
-      layerEnter.append("g").attr("class", "markers");
-      layer = layerEnter.merge(layer);
-      if (enabled) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          update();
-          service.loadImages(projection2);
-        } else {
-          editOff();
+      function accept(d3_event, d2) {
+        _cancelFetch = true;
+        var thiz = input.node();
+        if (d2) {
+          utilGetSetValue(input, d2.value);
+          utilTriggerEvent(input, "change");
+        }
+        var val = utilGetSetValue(input);
+        thiz.setSelectionRange(val.length, val.length);
+        if (!d2) {
+          d2 = _fetched[val];
         }
+        dispatch14.call("accept", thiz, d2, val);
+        hide();
       }
-    }
-    drawImages.enabled = function(_) {
-      if (!arguments.length)
-        return svgKartaviewImages.enabled;
-      svgKartaviewImages.enabled = _;
-      if (svgKartaviewImages.enabled) {
-        showLayer();
-        context.photos().on("change.kartaview_images", update);
-      } else {
-        hideLayer();
-        context.photos().on("change.kartaview_images", null);
+      function cancel() {
+        _cancelFetch = true;
+        var thiz = input.node();
+        var val = utilGetSetValue(input);
+        var start2 = input.property("selectionStart");
+        var end = input.property("selectionEnd");
+        val = val.slice(0, start2) + val.slice(end);
+        utilGetSetValue(input, val);
+        thiz.setSelectionRange(val.length, val.length);
+        dispatch14.call("cancel", thiz);
+        hide();
       }
-      dispatch10.call("change");
-      return this;
     };
-    drawImages.supported = function() {
-      return !!getService();
+    combobox.canAutocomplete = function(val) {
+      if (!arguments.length) return _canAutocomplete;
+      _canAutocomplete = val;
+      return combobox;
     };
-    init2();
-    return drawImages;
-  }
-
-  // modules/svg/osm.js
-  function svgOsm(projection2, context, dispatch10) {
-    var enabled = true;
-    function drawOsm(selection2) {
-      selection2.selectAll(".layer-osm").data(["covered", "areas", "lines", "points", "labels"]).enter().append("g").attr("class", function(d) {
-        return "layer-osm " + d;
-      });
-      selection2.selectAll(".layer-osm.points").selectAll(".points-group").data(["points", "midpoints", "vertices", "turns"]).enter().append("g").attr("class", function(d) {
-        return "points-group " + d;
-      });
-    }
-    function showLayer() {
-      var layer = context.surface().selectAll(".data-layer.osm");
-      layer.interrupt();
-      layer.classed("disabled", false).style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", function() {
-        dispatch10.call("change");
-      });
-    }
-    function hideLayer() {
-      var layer = context.surface().selectAll(".data-layer.osm");
-      layer.interrupt();
-      layer.transition().duration(250).style("opacity", 0).on("end interrupt", function() {
-        layer.classed("disabled", true);
-        dispatch10.call("change");
-      });
-    }
-    drawOsm.enabled = function(val) {
-      if (!arguments.length)
-        return enabled;
-      enabled = val;
-      if (enabled) {
-        showLayer();
-      } else {
-        hideLayer();
-      }
-      dispatch10.call("change");
-      return this;
+    combobox.caseSensitive = function(val) {
+      if (!arguments.length) return _caseSensitive;
+      _caseSensitive = val;
+      return combobox;
     };
-    return drawOsm;
+    combobox.data = function(val) {
+      if (!arguments.length) return _data;
+      _data = val;
+      return combobox;
+    };
+    combobox.fetcher = function(val) {
+      if (!arguments.length) return _fetcher;
+      _fetcher = val;
+      return combobox;
+    };
+    combobox.minItems = function(val) {
+      if (!arguments.length) return _minItems;
+      _minItems = val;
+      return combobox;
+    };
+    combobox.itemsMouseEnter = function(val) {
+      if (!arguments.length) return _mouseEnterHandler;
+      _mouseEnterHandler = val;
+      return combobox;
+    };
+    combobox.itemsMouseLeave = function(val) {
+      if (!arguments.length) return _mouseLeaveHandler;
+      _mouseLeaveHandler = val;
+      return combobox;
+    };
+    return utilRebind(combobox, dispatch14, "on");
   }
+  uiCombobox.off = function(input, context) {
+    input.on("focus.combo-input", null).on("blur.combo-input", null).on("keydown.combo-input", null).on("keyup.combo-input", null).on("input.combo-input", null).on("mousedown.combo-input", null).on("mouseup.combo-input", null);
+    context.container().on("scroll.combo-scroll", null);
+  };
 
-  // modules/svg/notes.js
-  var _notesEnabled = false;
-  var _osmService;
-  function svgNotes(projection2, context, dispatch10) {
-    if (!dispatch10) {
-      dispatch10 = dispatch_default("change");
-    }
-    var throttledRedraw = throttle_default(function() {
-      dispatch10.call("change");
-    }, 1e3);
-    var minZoom3 = 12;
-    var touchLayer = select_default2(null);
-    var drawLayer = select_default2(null);
-    var _notesVisible = false;
-    function markerPath(selection2, klass) {
-      selection2.attr("class", klass).attr("transform", "translate(-8, -22)").attr("d", "m17.5,0l-15,0c-1.37,0 -2.5,1.12 -2.5,2.5l0,11.25c0,1.37 1.12,2.5 2.5,2.5l3.75,0l0,3.28c0,0.38 0.43,0.6 0.75,0.37l4.87,-3.65l5.62,0c1.37,0 2.5,-1.12 2.5,-2.5l0,-11.25c0,-1.37 -1.12,-2.5 -2.5,-2.5z");
-    }
-    function getService() {
-      if (services.osm && !_osmService) {
-        _osmService = services.osm;
-        _osmService.on("loadedNotes", throttledRedraw);
-      } else if (!services.osm && _osmService) {
-        _osmService = null;
-      }
-      return _osmService;
-    }
-    function editOn() {
-      if (!_notesVisible) {
-        _notesVisible = true;
-        drawLayer.style("display", "block");
-      }
+  // modules/ui/intro/helper.js
+  function pointBox(loc, context) {
+    var rect = context.surfaceRect();
+    var point = context.curtainProjection(loc);
+    return {
+      left: point[0] + rect.left - 40,
+      top: point[1] + rect.top - 60,
+      width: 80,
+      height: 90
+    };
+  }
+  function pad(locOrBox, padding, context) {
+    var box;
+    if (locOrBox instanceof Array) {
+      var rect = context.surfaceRect();
+      var point = context.curtainProjection(locOrBox);
+      box = {
+        left: point[0] + rect.left,
+        top: point[1] + rect.top
+      };
+    } else {
+      box = locOrBox;
     }
-    function editOff() {
-      if (_notesVisible) {
-        _notesVisible = false;
-        drawLayer.style("display", "none");
-        drawLayer.selectAll(".note").remove();
-        touchLayer.selectAll(".note").remove();
+    return {
+      left: box.left - padding,
+      top: box.top - padding,
+      width: (box.width || 0) + 2 * padding,
+      height: (box.width || 0) + 2 * padding
+    };
+  }
+  function icon(name, svgklass, useklass) {
+    return '<svg class="icon ' + (svgklass || "") + '"><use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : "") + "></use></svg>";
+  }
+  var helpStringReplacements;
+  function helpHtml(id2, replacements) {
+    if (!helpStringReplacements) {
+      helpStringReplacements = {
+        // insert icons corresponding to various UI elements
+        point_icon: icon("#iD-icon-point", "inline"),
+        line_icon: icon("#iD-icon-line", "inline"),
+        area_icon: icon("#iD-icon-area", "inline"),
+        note_icon: icon("#iD-icon-note", "inline add-note"),
+        plus: icon("#iD-icon-plus", "inline"),
+        minus: icon("#iD-icon-minus", "inline"),
+        layers_icon: icon("#iD-icon-layers", "inline"),
+        data_icon: icon("#iD-icon-data", "inline"),
+        inspect: icon("#iD-icon-inspect", "inline"),
+        help_icon: icon("#iD-icon-help", "inline"),
+        undo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo", "inline"),
+        redo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-undo" : "#iD-icon-redo", "inline"),
+        save_icon: icon("#iD-icon-save", "inline"),
+        // operation icons
+        circularize_icon: icon("#iD-operation-circularize", "inline operation"),
+        continue_icon: icon("#iD-operation-continue", "inline operation"),
+        copy_icon: icon("#iD-operation-copy", "inline operation"),
+        delete_icon: icon("#iD-operation-delete", "inline operation"),
+        disconnect_icon: icon("#iD-operation-disconnect", "inline operation"),
+        downgrade_icon: icon("#iD-operation-downgrade", "inline operation"),
+        extract_icon: icon("#iD-operation-extract", "inline operation"),
+        merge_icon: icon("#iD-operation-merge", "inline operation"),
+        move_icon: icon("#iD-operation-move", "inline operation"),
+        orthogonalize_icon: icon("#iD-operation-orthogonalize", "inline operation"),
+        paste_icon: icon("#iD-operation-paste", "inline operation"),
+        reflect_long_icon: icon("#iD-operation-reflect-long", "inline operation"),
+        reflect_short_icon: icon("#iD-operation-reflect-short", "inline operation"),
+        reverse_icon: icon("#iD-operation-reverse", "inline operation"),
+        rotate_icon: icon("#iD-operation-rotate", "inline operation"),
+        split_icon: icon("#iD-operation-split", "inline operation"),
+        straighten_icon: icon("#iD-operation-straighten", "inline operation"),
+        // interaction icons
+        leftclick: icon("#iD-walkthrough-mouse-left", "inline operation"),
+        rightclick: icon("#iD-walkthrough-mouse-right", "inline operation"),
+        mousewheel_icon: icon("#iD-walkthrough-mousewheel", "inline operation"),
+        tap_icon: icon("#iD-walkthrough-tap", "inline operation"),
+        doubletap_icon: icon("#iD-walkthrough-doubletap", "inline operation"),
+        longpress_icon: icon("#iD-walkthrough-longpress", "inline operation"),
+        touchdrag_icon: icon("#iD-walkthrough-touchdrag", "inline operation"),
+        pinch_icon: icon("#iD-walkthrough-pinch-apart", "inline operation"),
+        // insert keys; may be localized and platform-dependent
+        shift: uiCmd.display("\u21E7"),
+        alt: uiCmd.display("\u2325"),
+        return: uiCmd.display("\u21B5"),
+        esc: _t.html("shortcuts.key.esc"),
+        space: _t.html("shortcuts.key.space"),
+        add_note_key: _t.html("modes.add_note.key"),
+        help_key: _t.html("help.key"),
+        shortcuts_key: _t.html("shortcuts.toggle.key"),
+        // reference localized UI labels directly so that they'll always match
+        save: _t.html("save.title"),
+        undo: _t.html("undo.title"),
+        redo: _t.html("redo.title"),
+        upload: _t.html("commit.save"),
+        point: _t.html("modes.add_point.title"),
+        line: _t.html("modes.add_line.title"),
+        area: _t.html("modes.add_area.title"),
+        note: _t.html("modes.add_note.label"),
+        circularize: _t.html("operations.circularize.title"),
+        continue: _t.html("operations.continue.title"),
+        copy: _t.html("operations.copy.title"),
+        delete: _t.html("operations.delete.title"),
+        disconnect: _t.html("operations.disconnect.title"),
+        downgrade: _t.html("operations.downgrade.title"),
+        extract: _t.html("operations.extract.title"),
+        merge: _t.html("operations.merge.title"),
+        move: _t.html("operations.move.title"),
+        orthogonalize: _t.html("operations.orthogonalize.title"),
+        paste: _t.html("operations.paste.title"),
+        reflect_long: _t.html("operations.reflect.title.long"),
+        reflect_short: _t.html("operations.reflect.title.short"),
+        reverse: _t.html("operations.reverse.title"),
+        rotate: _t.html("operations.rotate.title"),
+        split: _t.html("operations.split.title"),
+        straighten: _t.html("operations.straighten.title"),
+        map_data: _t.html("map_data.title"),
+        osm_notes: _t.html("map_data.layers.notes.title"),
+        fields: _t.html("inspector.fields"),
+        tags: _t.html("inspector.tags"),
+        relations: _t.html("inspector.relations"),
+        new_relation: _t.html("inspector.new_relation"),
+        turn_restrictions: _t.html("_tagging.presets.fields.restrictions.label"),
+        background_settings: _t.html("background.description"),
+        imagery_offset: _t.html("background.fix_misalignment"),
+        start_the_walkthrough: _t.html("splash.walkthrough"),
+        help: _t.html("help.title"),
+        ok: _t.html("intro.ok")
+      };
+      for (var key in helpStringReplacements) {
+        helpStringReplacements[key] = { html: helpStringReplacements[key] };
       }
     }
-    function layerOn() {
-      editOn();
-      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", function() {
-        dispatch10.call("change");
-      });
-    }
-    function layerOff() {
-      throttledRedraw.cancel();
-      drawLayer.interrupt();
-      touchLayer.selectAll(".note").remove();
-      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", function() {
-        editOff();
-        dispatch10.call("change");
-      });
+    var reps;
+    if (replacements) {
+      reps = Object.assign(replacements, helpStringReplacements);
+    } else {
+      reps = helpStringReplacements;
     }
-    function updateMarkers() {
-      if (!_notesVisible || !_notesEnabled)
-        return;
-      var service = getService();
-      var selectedID = context.selectedNoteID();
-      var data = service ? service.notes(projection2) : [];
-      var getTransform = svgPointTransform(projection2);
-      var notes = drawLayer.selectAll(".note").data(data, function(d) {
-        return d.status + d.id;
-      });
-      notes.exit().remove();
-      var notesEnter = notes.enter().append("g").attr("class", function(d) {
-        return "note note-" + d.id + " " + d.status;
-      }).classed("new", function(d) {
-        return d.id < 0;
-      });
-      notesEnter.append("ellipse").attr("cx", 0.5).attr("cy", 1).attr("rx", 6.5).attr("ry", 3).attr("class", "stroke");
-      notesEnter.append("path").call(markerPath, "shadow");
-      notesEnter.append("use").attr("class", "note-fill").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").attr("xlink:href", "#iD-icon-note");
-      notesEnter.selectAll(".icon-annotation").data(function(d) {
-        return [d];
-      }).enter().append("use").attr("class", "icon-annotation").attr("width", "10px").attr("height", "10px").attr("x", "-3px").attr("y", "-19px").attr("xlink:href", function(d) {
-        if (d.id < 0)
-          return "#iD-icon-plus";
-        if (d.status === "open")
-          return "#iD-icon-close";
-        return "#iD-icon-apply";
-      });
-      notes.merge(notesEnter).sort(sortY).classed("selected", function(d) {
-        var mode = context.mode();
-        var isMoving = mode && mode.id === "drag-note";
-        return !isMoving && d.id === selectedID;
-      }).attr("transform", getTransform);
-      if (touchLayer.empty())
-        return;
-      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
-      var targets = touchLayer.selectAll(".note").data(data, function(d) {
-        return d.id;
-      });
-      targets.exit().remove();
-      targets.enter().append("rect").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").merge(targets).sort(sortY).attr("class", function(d) {
-        var newClass = d.id < 0 ? "new" : "";
-        return "note target note-" + d.id + " " + fillClass + newClass;
-      }).attr("transform", getTransform);
-      function sortY(a, b) {
-        if (a.id === selectedID)
-          return 1;
-        if (b.id === selectedID)
-          return -1;
-        return b.loc[1] - a.loc[1];
-      }
+    return _t.html(id2, reps).replace(/\`(.*?)\`/g, "<kbd>$1</kbd>");
+  }
+  function slugify(text) {
+    return text.toString().toLowerCase().replace(/\s+/g, "-").replace(/[^\w\-]+/g, "").replace(/\-\-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
+  }
+  var missingStrings = {};
+  function checkKey(key, text) {
+    if (_t(key, { default: void 0 }) === void 0) {
+      if (missingStrings.hasOwnProperty(key)) return;
+      missingStrings[key] = text;
+      var missing = key + ": " + text;
+      if (typeof console !== "undefined") console.log(missing);
     }
-    function drawNotes(selection2) {
-      var service = getService();
-      var surface = context.surface();
-      if (surface && !surface.empty()) {
-        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
-      }
-      drawLayer = selection2.selectAll(".layer-notes").data(service ? [0] : []);
-      drawLayer.exit().remove();
-      drawLayer = drawLayer.enter().append("g").attr("class", "layer-notes").style("display", _notesEnabled ? "block" : "none").merge(drawLayer);
-      if (_notesEnabled) {
-        if (service && ~~context.map().zoom() >= minZoom3) {
-          editOn();
-          service.loadNotes(projection2);
-          updateMarkers();
-        } else {
-          editOff();
-        }
-      }
+  }
+  function localize(obj) {
+    var key;
+    var name = obj.tags && obj.tags.name;
+    if (name) {
+      key = "intro.graph.name." + slugify(name);
+      obj.tags.name = _t(key, { default: name });
+      checkKey(key, name);
     }
-    drawNotes.enabled = function(val) {
-      if (!arguments.length)
-        return _notesEnabled;
-      _notesEnabled = val;
-      if (_notesEnabled) {
-        layerOn();
-      } else {
-        layerOff();
-        if (context.selectedNoteID()) {
-          context.enter(modeBrowse(context));
+    var street = obj.tags && obj.tags["addr:street"];
+    if (street) {
+      key = "intro.graph.name." + slugify(street);
+      obj.tags["addr:street"] = _t(key, { default: street });
+      checkKey(key, street);
+      var addrTags = [
+        "block_number",
+        "city",
+        "county",
+        "district",
+        "hamlet",
+        "neighbourhood",
+        "postcode",
+        "province",
+        "quarter",
+        "state",
+        "subdistrict",
+        "suburb"
+      ];
+      addrTags.forEach(function(k2) {
+        var key2 = "intro.graph." + k2;
+        var tag2 = "addr:" + k2;
+        var val = obj.tags && obj.tags[tag2];
+        var str = _t(key2, { default: val });
+        if (str) {
+          if (str.match(/^<.*>$/) !== null) {
+            delete obj.tags[tag2];
+          } else {
+            obj.tags[tag2] = str;
+          }
         }
-      }
-      dispatch10.call("change");
-      return this;
-    };
-    return drawNotes;
-  }
-
-  // modules/svg/touch.js
-  function svgTouch() {
-    function drawTouch(selection2) {
-      selection2.selectAll(".layer-touch").data(["areas", "lines", "points", "turns", "markers"]).enter().append("g").attr("class", function(d) {
-        return "layer-touch " + d;
       });
     }
-    return drawTouch;
-  }
-
-  // modules/util/dimensions.js
-  function refresh(selection2, node) {
-    var cr = node.getBoundingClientRect();
-    var prop = [cr.width, cr.height];
-    selection2.property("__dimensions__", prop);
-    return prop;
+    return obj;
   }
-  function utilGetDimensions(selection2, force) {
-    if (!selection2 || selection2.empty()) {
-      return [0, 0];
+  function isMostlySquare(points) {
+    var threshold = 15;
+    var lowerBound = Math.cos((90 - threshold) * Math.PI / 180);
+    var upperBound = Math.cos(threshold * Math.PI / 180);
+    for (var i3 = 0; i3 < points.length; i3++) {
+      var a2 = points[(i3 - 1 + points.length) % points.length];
+      var origin = points[i3];
+      var b2 = points[(i3 + 1) % points.length];
+      var dotp = geoVecNormalizedDot(a2, b2, origin);
+      var mag = Math.abs(dotp);
+      if (mag > lowerBound && mag < upperBound) {
+        return false;
+      }
     }
-    var node = selection2.node(), cached = selection2.property("__dimensions__");
-    return !cached || force ? refresh(selection2, node) : cached;
+    return true;
   }
-  function utilSetDimensions(selection2, dimensions) {
-    if (!selection2 || selection2.empty()) {
-      return selection2;
-    }
-    var node = selection2.node();
-    if (dimensions === null) {
-      refresh(selection2, node);
-      return selection2;
+  function selectMenuItem(context, operation2) {
+    return context.container().select(".edit-menu .edit-menu-item-" + operation2);
+  }
+  function transitionTime(point1, point2) {
+    var distance = geoSphericalDistance(point1, point2);
+    if (distance === 0) {
+      return 0;
+    } else if (distance < 80) {
+      return 500;
+    } else {
+      return 1e3;
     }
-    return selection2.property("__dimensions__", [dimensions[0], dimensions[1]]).attr("width", dimensions[0]).attr("height", dimensions[1]);
   }
 
-  // modules/svg/layers.js
-  function svgLayers(projection2, context) {
-    var dispatch10 = dispatch_default("change");
-    var svg2 = select_default2(null);
-    var _layers = [
-      { id: "osm", layer: svgOsm(projection2, context, dispatch10) },
-      { id: "notes", layer: svgNotes(projection2, context, dispatch10) },
-      { id: "data", layer: svgData(projection2, context, dispatch10) },
-      { id: "keepRight", layer: svgKeepRight(projection2, context, dispatch10) },
-      { id: "improveOSM", layer: svgImproveOSM(projection2, context, dispatch10) },
-      { id: "osmose", layer: svgOsmose(projection2, context, dispatch10) },
-      { id: "streetside", layer: svgStreetside(projection2, context, dispatch10) },
-      { id: "mapillary", layer: svgMapillaryImages(projection2, context, dispatch10) },
-      { id: "mapillary-position", layer: svgMapillaryPosition(projection2, context, dispatch10) },
-      { id: "mapillary-map-features", layer: svgMapillaryMapFeatures(projection2, context, dispatch10) },
-      { id: "mapillary-signs", layer: svgMapillarySigns(projection2, context, dispatch10) },
-      { id: "kartaview", layer: svgKartaviewImages(projection2, context, dispatch10) },
-      { id: "debug", layer: svgDebug(projection2, context, dispatch10) },
-      { id: "geolocate", layer: svgGeolocate(projection2, context, dispatch10) },
-      { id: "touch", layer: svgTouch(projection2, context, dispatch10) }
-    ];
-    function drawLayers(selection2) {
-      svg2 = selection2.selectAll(".surface").data([0]);
-      svg2 = svg2.enter().append("svg").attr("class", "surface").merge(svg2);
-      var defs = svg2.selectAll(".surface-defs").data([0]);
-      defs.enter().append("defs").attr("class", "surface-defs");
-      var groups = svg2.selectAll(".data-layer").data(_layers);
-      groups.exit().remove();
-      groups.enter().append("g").attr("class", function(d) {
-        return "data-layer " + d.id;
-      }).merge(groups).each(function(d) {
-        select_default2(this).call(d.layer);
-      });
-    }
-    drawLayers.all = function() {
-      return _layers;
+  // modules/ui/field_help.js
+  function uiFieldHelp(context, fieldName) {
+    var fieldHelp = {};
+    var _inspector = select_default2(null);
+    var _wrap = select_default2(null);
+    var _body = select_default2(null);
+    var fieldHelpKeys = {
+      restrictions: [
+        ["about", [
+          "about",
+          "from_via_to",
+          "maxdist",
+          "maxvia"
+        ]],
+        ["inspecting", [
+          "about",
+          "from_shadow",
+          "allow_shadow",
+          "restrict_shadow",
+          "only_shadow",
+          "restricted",
+          "only"
+        ]],
+        ["modifying", [
+          "about",
+          "indicators",
+          "allow_turn",
+          "restrict_turn",
+          "only_turn"
+        ]],
+        ["tips", [
+          "simple",
+          "simple_example",
+          "indirect",
+          "indirect_example",
+          "indirect_noedit"
+        ]]
+      ]
     };
-    drawLayers.layer = function(id2) {
-      var obj = _layers.find(function(o) {
-        return o.id === id2;
-      });
-      return obj && obj.layer;
+    var fieldHelpHeadings = {};
+    var replacements = {
+      distField: { html: _t.html("restriction.controls.distance") },
+      viaField: { html: _t.html("restriction.controls.via") },
+      fromShadow: { html: icon("#iD-turn-shadow", "inline shadow from") },
+      allowShadow: { html: icon("#iD-turn-shadow", "inline shadow allow") },
+      restrictShadow: { html: icon("#iD-turn-shadow", "inline shadow restrict") },
+      onlyShadow: { html: icon("#iD-turn-shadow", "inline shadow only") },
+      allowTurn: { html: icon("#iD-turn-yes", "inline turn") },
+      restrictTurn: { html: icon("#iD-turn-no", "inline turn") },
+      onlyTurn: { html: icon("#iD-turn-only", "inline turn") }
     };
-    drawLayers.only = function(what) {
-      var arr = [].concat(what);
-      var all = _layers.map(function(layer) {
-        return layer.id;
+    var docs = fieldHelpKeys[fieldName].map(function(key) {
+      var helpkey = "help.field." + fieldName + "." + key[0];
+      var text = key[1].reduce(function(all, part) {
+        var subkey = helpkey + "." + part;
+        var depth = fieldHelpHeadings[subkey];
+        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
+        return all + hhh + _t.html(subkey, replacements) + "\n\n";
+      }, "");
+      return {
+        key: helpkey,
+        title: _t.html(helpkey + ".title"),
+        html: marked(text.trim())
+      };
+    });
+    function show() {
+      updatePosition();
+      _body.classed("hide", false).style("opacity", "0").transition().duration(200).style("opacity", "1");
+    }
+    function hide() {
+      _body.classed("hide", true).transition().duration(200).style("opacity", "0").on("end", function() {
+        _body.classed("hide", true);
       });
-      return drawLayers.remove(utilArrayDifference(all, arr));
-    };
-    drawLayers.remove = function(what) {
-      var arr = [].concat(what);
-      arr.forEach(function(id2) {
-        _layers = _layers.filter(function(o) {
-          return o.id !== id2;
-        });
+    }
+    function clickHelp(index) {
+      var d2 = docs[index];
+      var tkeys = fieldHelpKeys[fieldName][index][1];
+      _body.selectAll(".field-help-nav-item").classed("active", function(d4, i3) {
+        return i3 === index;
       });
-      dispatch10.call("change");
-      return this;
-    };
-    drawLayers.add = function(what) {
-      var arr = [].concat(what);
-      arr.forEach(function(obj) {
-        if ("id" in obj && "layer" in obj) {
-          _layers.push(obj);
+      var content = _body.selectAll(".field-help-content").html(d2.html);
+      content.selectAll("p").attr("class", function(d4, i3) {
+        return tkeys[i3];
+      });
+      if (d2.key === "help.field.restrictions.inspecting") {
+        content.insert("img", "p.from_shadow").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_inspect.gif"));
+      } else if (d2.key === "help.field.restrictions.modifying") {
+        content.insert("img", "p.allow_turn").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_modify.gif"));
+      }
+    }
+    fieldHelp.button = function(selection2) {
+      if (_body.empty()) return;
+      var button = selection2.selectAll(".field-help-button").data([0]);
+      button.enter().append("button").attr("class", "field-help-button").call(svgIcon("#iD-icon-help")).merge(button).on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        if (_body.classed("hide")) {
+          show();
+        } else {
+          hide();
         }
       });
-      dispatch10.call("change");
-      return this;
     };
-    drawLayers.dimensions = function(val) {
-      if (!arguments.length)
-        return utilGetDimensions(svg2);
-      utilSetDimensions(svg2, val);
-      return this;
+    function updatePosition() {
+      var wrap2 = _wrap.node();
+      var inspector = _inspector.node();
+      var wRect = wrap2.getBoundingClientRect();
+      var iRect = inspector.getBoundingClientRect();
+      _body.style("top", wRect.top + inspector.scrollTop - iRect.top + "px");
+    }
+    fieldHelp.body = function(selection2) {
+      _wrap = selection2.selectAll(".form-field-input-wrap");
+      if (_wrap.empty()) return;
+      _inspector = context.container().select(".sidebar .entity-editor-pane .inspector-body");
+      if (_inspector.empty()) return;
+      _body = _inspector.selectAll(".field-help-body").data([0]);
+      var enter = _body.enter().append("div").attr("class", "field-help-body hide");
+      var titleEnter = enter.append("div").attr("class", "field-help-title cf");
+      titleEnter.append("h2").attr("class", _mainLocalizer.textDirection() === "rtl" ? "fr" : "fl").call(_t.append("help.field." + fieldName + ".title"));
+      titleEnter.append("button").attr("class", "fr close").attr("title", _t("icons.close")).on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        hide();
+      }).call(svgIcon("#iD-icon-close"));
+      var navEnter = enter.append("div").attr("class", "field-help-nav cf");
+      var titles = docs.map(function(d2) {
+        return d2.title;
+      });
+      navEnter.selectAll(".field-help-nav-item").data(titles).enter().append("div").attr("class", "field-help-nav-item").html(function(d2) {
+        return d2;
+      }).on("click", function(d3_event, d2) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        clickHelp(titles.indexOf(d2));
+      });
+      enter.append("div").attr("class", "field-help-content");
+      _body = _body.merge(enter);
+      clickHelp(0);
     };
-    return utilRebind(drawLayers, dispatch10, "on");
+    return fieldHelp;
   }
 
-  // modules/svg/lines.js
-  var import_fast_deep_equal6 = __toESM(require_fast_deep_equal());
-  function svgLines(projection2, context) {
-    var detected = utilDetect();
-    var highway_stack = {
-      motorway: 0,
-      motorway_link: 1,
-      trunk: 2,
-      trunk_link: 3,
-      primary: 4,
-      primary_link: 5,
-      secondary: 6,
-      tertiary: 7,
-      unclassified: 8,
-      residential: 9,
-      service: 10,
-      footway: 11
-    };
-    function drawTargets(selection2, graph, entities, filter2) {
-      var targetClass = context.getDebug("target") ? "pink " : "nocolor ";
-      var nopeClass = context.getDebug("target") ? "red " : "nocolor ";
-      var getPath = svgPath(projection2).geojson;
-      var activeID = context.activeID();
-      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 targetData = data.targets.filter(getPath);
-      var targets = selection2.selectAll(".line.target-allowed").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(targetData, function key(d) {
-        return d.id;
-      });
-      targets.exit().remove();
-      var segmentWasEdited = function(d) {
-        var wayID = d.properties.entity.id;
-        if (!base.entities[wayID] || !(0, import_fast_deep_equal6.default)(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
-          return false;
-        }
-        return d.properties.nodes.some(function(n2) {
-          return !base.entities[n2.id] || !(0, import_fast_deep_equal6.default)(graph.entities[n2.id].loc, base.entities[n2.id].loc);
-        });
-      };
-      targets.enter().append("path").merge(targets).attr("d", getPath).attr("class", function(d) {
-        return "way line target target-allowed " + targetClass + d.id;
-      }).classed("segment-edited", segmentWasEdited);
-      var nopeData = data.nopes.filter(getPath);
-      var nopes = selection2.selectAll(".line.target-nope").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(nopeData, function key(d) {
-        return d.id;
-      });
-      nopes.exit().remove();
-      nopes.enter().append("path").merge(nopes).attr("d", getPath).attr("class", function(d) {
-        return "way line target target-nope " + nopeClass + d.id;
-      }).classed("segment-edited", segmentWasEdited);
+  // modules/ui/fields/check.js
+  function uiFieldCheck(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var options2 = field.options;
+    var values = [];
+    var texts = [];
+    var _tags;
+    var input = select_default2(null);
+    var text = select_default2(null);
+    var label = select_default2(null);
+    var reverser = select_default2(null);
+    var _impliedYes;
+    var _entityIDs = [];
+    var _value;
+    var stringsField = field.resolveReference("stringsCrossReference");
+    if (!options2 && stringsField.options) {
+      options2 = stringsField.options;
     }
-    function drawLines(selection2, graph, entities, filter2) {
-      var base = context.history().base();
-      function waystack(a, b) {
-        var selected = context.selectedIDs();
-        var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
-        var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
-        if (a.tags.highway) {
-          scoreA -= highway_stack[a.tags.highway];
-        }
-        if (b.tags.highway) {
-          scoreB -= highway_stack[b.tags.highway];
-        }
-        return scoreA - scoreB;
+    if (options2) {
+      for (var i3 in options2) {
+        var v2 = options2[i3];
+        values.push(v2 === "undefined" ? void 0 : v2);
+        texts.push(stringsField.t.html("options." + v2, { "default": v2 }));
       }
-      function drawLineGroup(selection3, klass, isSelected) {
-        var mode = context.mode();
-        var isDrawing = mode && /^draw/.test(mode.id);
-        var selectedClass = !isDrawing && isSelected ? "selected " : "";
-        var lines = selection3.selectAll("path").filter(filter2).data(getPathData(isSelected), osmEntity.key);
-        lines.exit().remove();
-        lines.enter().append("path").attr("class", function(d) {
-          var prefix = "way line";
-          if (!d.hasInterestingTags()) {
-            var parentRelations = graph.parentRelations(d);
-            var parentMultipolygons = parentRelations.filter(function(relation) {
-              return relation.isMultipolygon();
-            });
-            if (parentMultipolygons.length > 0 && parentRelations.length === parentMultipolygons.length) {
-              prefix = "relation area";
-            }
-          }
-          var oldMPClass = oldMultiPolygonOuters[d.id] ? "old-multipolygon " : "";
-          return prefix + " " + klass + " " + selectedClass + oldMPClass + d.id;
-        }).classed("added", function(d) {
-          return !base.entities[d.id];
-        }).classed("geometry-edited", function(d) {
-          return graph.entities[d.id] && base.entities[d.id] && !(0, import_fast_deep_equal6.default)(graph.entities[d.id].nodes, base.entities[d.id].nodes);
-        }).classed("retagged", function(d) {
-          return graph.entities[d.id] && base.entities[d.id] && !(0, import_fast_deep_equal6.default)(graph.entities[d.id].tags, base.entities[d.id].tags);
-        }).call(svgTagClasses()).merge(lines).sort(waystack).attr("d", getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
-        return selection3;
-      }
-      function getPathData(isSelected) {
-        return function() {
-          var layer = this.parentNode.__data__;
-          var data = pathdata[layer] || [];
-          return data.filter(function(d) {
-            if (isSelected) {
-              return context.selectedIDs().indexOf(d.id) !== -1;
-            } else {
-              return context.selectedIDs().indexOf(d.id) === -1;
-            }
-          });
-        };
+    } else {
+      values = [void 0, "yes"];
+      texts = [_t.html("inspector.unknown"), _t.html("inspector.check.yes")];
+      if (field.type !== "defaultCheck") {
+        values.push("no");
+        texts.push(_t.html("inspector.check.no"));
       }
-      function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
-        var markergroup = layergroup.selectAll("g." + groupclass).data([pathclass]);
-        markergroup = markergroup.enter().append("g").attr("class", groupclass).merge(markergroup);
-        var markers = markergroup.selectAll("path").filter(filter2).data(
-          function data() {
-            return groupdata[this.parentNode.__data__] || [];
-          },
-          function key(d) {
-            return [d.id, d.index];
+    }
+    function checkImpliedYes() {
+      _impliedYes = field.id === "oneway_yes";
+      if (field.id === "oneway") {
+        var entity = context.entity(_entityIDs[0]);
+        for (var key in entity.tags) {
+          if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
+            _impliedYes = true;
+            texts[0] = _t.html("_tagging.presets.fields.oneway_yes.options.undefined");
+            break;
           }
-        );
-        markers.exit().remove();
-        markers = markers.enter().append("path").attr("class", pathclass).merge(markers).attr("marker-mid", marker).attr("d", function(d) {
-          return d.d;
-        });
-        if (detected.ie) {
-          markers.each(function() {
-            this.parentNode.insertBefore(this, this);
-          });
         }
       }
-      var getPath = svgPath(projection2, graph);
-      var ways = [];
-      var onewaydata = {};
-      var sideddata = {};
-      var oldMultiPolygonOuters = {};
-      for (var i2 = 0; i2 < entities.length; i2++) {
-        var entity = entities[i2];
-        var outer = osmOldMultipolygonOuterMember(entity, graph);
-        if (outer) {
-          ways.push(entity.mergeTags(outer.tags));
-          oldMultiPolygonOuters[outer.id] = true;
-        } else if (entity.geometry(graph) === "line" || entity.geometry(graph) === "area" && entity.sidednessIdentifier && entity.sidednessIdentifier() === "coastline") {
-          ways.push(entity);
-        }
+    }
+    function reverserHidden() {
+      if (!context.container().select("div.inspector-hover").empty()) return true;
+      return !(_value === "yes" || _impliedYes && !_value);
+    }
+    function reverserSetText(selection2) {
+      var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
+      if (reverserHidden() || !entity) return selection2;
+      var first = entity.first();
+      var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
+      var pseudoDirection = first < last;
+      var icon2 = pseudoDirection ? "#iD-icon-forward" : "#iD-icon-backward";
+      selection2.selectAll(".reverser-span").html("").call(_t.append("inspector.check.reverser")).call(svgIcon(icon2, "inline"));
+      return selection2;
+    }
+    var check = function(selection2) {
+      checkImpliedYes();
+      label = selection2.selectAll(".form-field-input-wrap").data([0]);
+      var enter = label.enter().append("label").attr("class", "form-field-input-wrap form-field-input-check");
+      enter.append("input").property("indeterminate", field.type !== "defaultCheck").attr("type", "checkbox").attr("id", field.domId);
+      enter.append("span").html(texts[0]).attr("class", "value");
+      if (field.type === "onewayCheck") {
+        enter.append("button").attr("class", "reverser" + (reverserHidden() ? " hide" : "")).append("span").attr("class", "reverser-span");
       }
-      ways = ways.filter(getPath);
-      var pathdata = utilArrayGroupBy(ways, function(way) {
-        return way.layer();
-      });
-      Object.keys(pathdata).forEach(function(k) {
-        var v = pathdata[k];
-        var onewayArr = v.filter(function(d) {
-          return d.isOneWay();
-        });
-        var onewaySegments = svgMarkerSegments(
-          projection2,
-          graph,
-          35,
-          function shouldReverse(entity2) {
-            return entity2.tags.oneway === "-1";
-          },
-          function bothDirections(entity2) {
-            return entity2.tags.oneway === "reversible" || entity2.tags.oneway === "alternating";
-          }
-        );
-        onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
-        var sidedArr = v.filter(function(d) {
-          return d.isSided();
-        });
-        var sidedSegments = svgMarkerSegments(
-          projection2,
-          graph,
-          30,
-          function shouldReverse() {
-            return false;
-          },
-          function bothDirections() {
-            return false;
+      label = label.merge(enter);
+      input = label.selectAll("input");
+      text = label.selectAll("span.value");
+      input.on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        var t2 = {};
+        if (Array.isArray(_tags[field.key])) {
+          if (values.indexOf("yes") !== -1) {
+            t2[field.key] = "yes";
+          } else {
+            t2[field.key] = values[0];
           }
-        );
-        sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
+        } else {
+          t2[field.key] = values[(values.indexOf(_value) + 1) % values.length];
+        }
+        if (t2[field.key] === "reversible" || t2[field.key] === "alternating") {
+          t2[field.key] = values[0];
+        }
+        dispatch14.call("change", this, t2);
       });
-      var covered = selection2.selectAll(".layer-osm.covered");
-      var uncovered = selection2.selectAll(".layer-osm.lines");
-      var touchLayer = selection2.selectAll(".layer-touch.lines");
-      [covered, uncovered].forEach(function(selection3) {
-        var range3 = selection3 === covered ? range(-10, 0) : range(0, 11);
-        var layergroup = selection3.selectAll("g.layergroup").data(range3);
-        layergroup = layergroup.enter().append("g").attr("class", function(d) {
-          return "layergroup layer" + String(d);
-        }).merge(layergroup);
-        layergroup.selectAll("g.linegroup").data(["shadow", "casing", "stroke", "shadow-highlighted", "casing-highlighted", "stroke-highlighted"]).enter().append("g").attr("class", function(d) {
-          return "linegroup line-" + d;
+      if (field.type === "onewayCheck") {
+        reverser = label.selectAll(".reverser");
+        reverser.call(reverserSetText).on("click", function(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          context.perform(
+            function(graph) {
+              for (var i4 in _entityIDs) {
+                graph = actionReverse(_entityIDs[i4])(graph);
+              }
+              return graph;
+            },
+            _t("operations.reverse.annotation.line", { n: 1 })
+          );
+          context.validator().validate();
+          select_default2(this).call(reverserSetText);
         });
-        layergroup.selectAll("g.line-shadow").call(drawLineGroup, "shadow", false);
-        layergroup.selectAll("g.line-casing").call(drawLineGroup, "casing", false);
-        layergroup.selectAll("g.line-stroke").call(drawLineGroup, "stroke", false);
-        layergroup.selectAll("g.line-shadow-highlighted").call(drawLineGroup, "shadow", true);
-        layergroup.selectAll("g.line-casing-highlighted").call(drawLineGroup, "casing", true);
-        layergroup.selectAll("g.line-stroke-highlighted").call(drawLineGroup, "stroke", true);
-        addMarkers(layergroup, "oneway", "onewaygroup", onewaydata, "url(#ideditor-oneway-marker)");
-        addMarkers(
-          layergroup,
-          "sided",
-          "sidedgroup",
-          sideddata,
-          function marker(d) {
-            var category = graph.entity(d.id).sidednessIdentifier();
-            return "url(#ideditor-sided-marker-" + category + ")";
-          }
-        );
-      });
-      touchLayer.call(drawTargets, graph, ways, filter2);
-    }
-    return drawLines;
+      }
+    };
+    check.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return check;
+    };
+    check.tags = function(tags) {
+      _tags = tags;
+      function isChecked(val) {
+        return val !== "no" && val !== "" && val !== void 0 && val !== null;
+      }
+      function textFor(val) {
+        if (val === "") val = void 0;
+        var index = values.indexOf(val);
+        return index !== -1 ? texts[index] : '"' + val + '"';
+      }
+      checkImpliedYes();
+      var isMixed = Array.isArray(tags[field.key]);
+      _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
+      if (field.type === "onewayCheck" && (_value === "1" || _value === "-1")) {
+        _value = "yes";
+      }
+      input.property("indeterminate", isMixed || field.type !== "defaultCheck" && !_value).property("checked", isChecked(_value));
+      text.html(isMixed ? _t.html("inspector.multiple_values") : textFor(_value)).classed("mixed", isMixed);
+      label.classed("set", !!_value);
+      if (field.type === "onewayCheck") {
+        reverser.classed("hide", reverserHidden()).call(reverserSetText);
+      }
+    };
+    check.focus = function() {
+      input.node().focus();
+    };
+    return utilRebind(check, dispatch14, "on");
   }
 
-  // modules/svg/midpoints.js
-  function svgMidpoints(projection2, context) {
-    var targetRadius = 8;
-    function drawTargets(selection2, graph, entities, filter2) {
-      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
-      var getTransform = svgPointTransform(projection2).geojson;
-      var data = entities.map(function(midpoint) {
-        return {
-          type: "Feature",
-          id: midpoint.id,
-          properties: {
-            target: true,
-            entity: midpoint
-          },
-          geometry: {
-            type: "Point",
-            coordinates: midpoint.loc
+  // modules/svg/areas.js
+  var import_fast_deep_equal5 = __toESM(require_fast_deep_equal());
+
+  // modules/svg/helpers.js
+  function svgPassiveVertex(node, graph, activeID) {
+    if (!activeID) return 1;
+    if (activeID === node.id) return 0;
+    var parents = graph.parentWays(node);
+    var i3, j2, nodes, isClosed, ix1, ix2, ix3, ix4, max3;
+    for (i3 = 0; i3 < parents.length; i3++) {
+      nodes = parents[i3].nodes;
+      isClosed = parents[i3].isClosed();
+      for (j2 = 0; j2 < nodes.length; j2++) {
+        if (nodes[j2] === node.id) {
+          ix1 = j2 - 2;
+          ix2 = j2 - 1;
+          ix3 = j2 + 1;
+          ix4 = j2 + 2;
+          if (isClosed) {
+            max3 = nodes.length - 1;
+            if (ix1 < 0) ix1 = max3 + ix1;
+            if (ix2 < 0) ix2 = max3 + ix2;
+            if (ix3 > max3) ix3 = ix3 - max3;
+            if (ix4 > max3) ix4 = ix4 - max3;
           }
-        };
-      });
-      var targets = selection2.selectAll(".midpoint.target").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(data, function key(d) {
-        return d.id;
-      });
-      targets.exit().remove();
-      targets.enter().append("circle").attr("r", targetRadius).merge(targets).attr("class", function(d) {
-        return "node midpoint target " + fillClass + d.id;
-      }).attr("transform", getTransform);
+          if (nodes[ix1] === activeID) return 0;
+          else if (nodes[ix2] === activeID) return 2;
+          else if (nodes[ix3] === activeID) return 2;
+          else if (nodes[ix4] === activeID) return 0;
+          else if (isClosed && nodes.indexOf(activeID) !== -1) return 0;
+        }
+      }
     }
-    function drawMidpoints(selection2, graph, entities, filter2, extent) {
-      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.midpoints");
-      var touchLayer = selection2.selectAll(".layer-touch.points");
-      var mode = context.mode();
-      if (mode && mode.id !== "select" || !context.map().withinEditableZoom()) {
-        drawLayer.selectAll(".midpoint").remove();
-        touchLayer.selectAll(".midpoint.target").remove();
-        return;
+    return 1;
+  }
+  function svgMarkerSegments(projection2, graph, dt2, shouldReverse, bothDirections) {
+    return function(entity) {
+      var i3 = 0;
+      var offset = dt2;
+      var segments = [];
+      var clip = identity_default2().clipExtent(projection2.clipExtent()).stream;
+      var coordinates = graph.childNodes(entity).map(function(n3) {
+        return n3.loc;
+      });
+      var a2, b2;
+      if (shouldReverse(entity)) {
+        coordinates.reverse();
       }
-      var poly = extent.polygon();
-      var midpoints = {};
-      for (var i2 = 0; i2 < entities.length; i2++) {
-        var entity = entities[i2];
-        if (entity.type !== "way")
-          continue;
-        if (!filter2(entity))
-          continue;
-        if (context.selectedIDs().indexOf(entity.id) < 0)
-          continue;
-        var nodes = graph.childNodes(entity);
-        for (var j2 = 0; j2 < nodes.length - 1; j2++) {
-          var a = nodes[j2];
-          var b = nodes[j2 + 1];
-          var id2 = [a.id, b.id].sort().join("-");
-          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 loc = null;
-            if (extent.intersects(point)) {
-              loc = point;
-            } 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;
-                  break;
+      stream_default({
+        type: "LineString",
+        coordinates
+      }, projection2.stream(clip({
+        lineStart: function() {
+        },
+        lineEnd: function() {
+          a2 = null;
+        },
+        point: function(x2, y2) {
+          b2 = [x2, y2];
+          if (a2) {
+            var span = geoVecLength(a2, b2) - offset;
+            if (span >= 0) {
+              var heading2 = geoVecAngle(a2, b2);
+              var dx = dt2 * Math.cos(heading2);
+              var dy = dt2 * Math.sin(heading2);
+              var p2 = [
+                a2[0] + offset * Math.cos(heading2),
+                a2[1] + offset * Math.sin(heading2)
+              ];
+              var coord2 = [a2, p2];
+              for (span -= dt2; span >= 0; span -= dt2) {
+                p2 = geoVecAdd(p2, [dx, dy]);
+                coord2.push(p2);
+              }
+              coord2.push(b2);
+              var segment = "";
+              var j2;
+              for (j2 = 0; j2 < coord2.length; j2++) {
+                segment += (j2 === 0 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
+              }
+              segments.push({ id: entity.id, index: i3++, d: segment });
+              if (bothDirections(entity)) {
+                segment = "";
+                for (j2 = coord2.length - 1; j2 >= 0; j2--) {
+                  segment += (j2 === coord2.length - 1 ? "M" : "L") + coord2[j2][0] + "," + coord2[j2][1];
                 }
+                segments.push({ id: entity.id, index: i3++, d: segment });
               }
             }
-            if (loc) {
-              midpoints[id2] = {
-                type: "midpoint",
-                id: id2,
-                loc,
-                edge: [a.id, b.id],
-                parents: [entity]
-              };
-            }
+            offset = -span;
           }
+          a2 = b2;
         }
+      })));
+      return segments;
+    };
+  }
+  function svgPath(projection2, graph, isArea) {
+    var cache = {};
+    var padding = isArea ? 65 : 5;
+    var viewport = projection2.clipExtent();
+    var paddedExtent = [
+      [viewport[0][0] - padding, viewport[0][1] - padding],
+      [viewport[1][0] + padding, viewport[1][1] + padding]
+    ];
+    var clip = identity_default2().clipExtent(paddedExtent).stream;
+    var project = projection2.stream;
+    var path = path_default().projection({ stream: function(output) {
+      return project(clip(output));
+    } });
+    var svgpath = function(entity) {
+      if (entity.id in cache) {
+        return cache[entity.id];
+      } else {
+        return cache[entity.id] = path(entity.asGeoJSON(graph));
       }
-      function midpointFilter(d) {
-        if (midpoints[d.id])
-          return true;
-        for (var i3 = 0; i3 < d.parents.length; i3++) {
-          if (filter2(d.parents[i3])) {
-            return true;
-          }
+    };
+    svgpath.geojson = function(d2) {
+      if (d2.__featurehash__ !== void 0) {
+        if (d2.__featurehash__ in cache) {
+          return cache[d2.__featurehash__];
+        } else {
+          return cache[d2.__featurehash__] = path(d2);
         }
-        return false;
+      } else {
+        return path(d2);
       }
-      var groups = drawLayer.selectAll(".midpoint").filter(midpointFilter).data(Object.values(midpoints), function(d) {
-        return d.id;
-      });
-      groups.exit().remove();
-      var enter = groups.enter().insert("g", ":first-child").attr("class", "midpoint");
-      enter.append("polygon").attr("points", "-6,8 10,0 -6,-8").attr("class", "shadow");
-      enter.append("polygon").attr("points", "-3,4 5,0 -3,-4").attr("class", "fill");
-      groups = groups.merge(enter).attr("transform", function(d) {
-        var translate = svgPointTransform(projection2);
-        var a2 = graph.entity(d.edge[0]);
-        var b2 = graph.entity(d.edge[1]);
-        var angle2 = geoAngle(a2, b2, projection2) * (180 / Math.PI);
-        return translate(d) + " rotate(" + angle2 + ")";
-      }).call(svgTagClasses().tags(
-        function(d) {
-          return d.parents[0].tags;
+    };
+    return svgpath;
+  }
+  function svgPointTransform(projection2) {
+    var svgpoint = function(entity) {
+      var pt2 = projection2(entity.loc);
+      return "translate(" + pt2[0] + "," + pt2[1] + ")";
+    };
+    svgpoint.geojson = function(d2) {
+      return svgpoint(d2.properties.entity);
+    };
+    return svgpoint;
+  }
+  function svgRelationMemberTags(graph) {
+    return function(entity) {
+      var tags = entity.tags;
+      var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
+      graph.parentRelations(entity).forEach(function(relation) {
+        var type2 = relation.tags.type;
+        if (type2 === "multipolygon" && shouldCopyMultipolygonTags || type2 === "boundary") {
+          tags = Object.assign({}, relation.tags, tags);
         }
-      ));
-      groups.select("polygon.shadow");
-      groups.select("polygon.fill");
-      touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
-    }
-    return drawMidpoints;
+      });
+      return tags;
+    };
   }
-
-  // modules/svg/points.js
-  var import_fast_deep_equal7 = __toESM(require_fast_deep_equal());
-  function svgPoints(projection2, context) {
-    function markerPath(selection2, klass) {
-      selection2.attr("class", klass).attr("transform", "translate(-8, -23)").attr("d", "M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z");
-    }
-    function sortY(a, b) {
-      return b.loc[1] - a.loc[1];
-    }
-    function fastEntityKey(d) {
-      var mode = context.mode();
-      var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
-      return isMoving ? d.id : osmEntity.key(d);
+  function svgSegmentWay(way, graph, activeID) {
+    if (activeID === void 0) {
+      return graph.transient(way, "waySegments", getWaySegments);
+    } else {
+      return getWaySegments();
     }
-    function drawTargets(selection2, graph, entities, filter2) {
-      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
-      var getTransform = svgPointTransform(projection2).geojson;
-      var activeID = context.activeID();
-      var data = [];
-      entities.forEach(function(node) {
-        if (activeID === node.id)
-          return;
-        data.push({
+    function getWaySegments() {
+      var isActiveWay = way.nodes.indexOf(activeID) !== -1;
+      var features = { passive: [], active: [] };
+      var start2 = {};
+      var end = {};
+      var node, type2;
+      for (var i3 = 0; i3 < way.nodes.length; i3++) {
+        node = graph.entity(way.nodes[i3]);
+        type2 = svgPassiveVertex(node, graph, activeID);
+        end = { node, type: type2 };
+        if (start2.type !== void 0) {
+          if (start2.node.id === activeID || end.node.id === activeID) {
+          } else if (isActiveWay && (start2.type === 2 || end.type === 2)) {
+            pushActive(start2, end, i3);
+          } else if (start2.type === 0 && end.type === 0) {
+            pushActive(start2, end, i3);
+          } else {
+            pushPassive(start2, end, i3);
+          }
+        }
+        start2 = end;
+      }
+      return features;
+      function pushActive(start3, end2, index) {
+        features.active.push({
           type: "Feature",
-          id: node.id,
+          id: way.id + "-" + index + "-nope",
           properties: {
+            nope: true,
             target: true,
-            entity: node
+            entity: way,
+            nodes: [start3.node, end2.node],
+            index
           },
-          geometry: node.asGeoJSON()
+          geometry: {
+            type: "LineString",
+            coordinates: [start3.node.loc, end2.node.loc]
+          }
         });
-      });
-      var targets = selection2.selectAll(".point.target").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(data, function key(d) {
-        return d.id;
-      });
-      targets.exit().remove();
-      targets.enter().append("rect").attr("x", -10).attr("y", -26).attr("width", 20).attr("height", 30).merge(targets).attr("class", function(d) {
-        return "node point target " + fillClass + d.id;
-      }).attr("transform", getTransform);
-    }
-    function drawPoints(selection2, graph, entities, filter2) {
-      var wireframe = context.surface().classed("fill-wireframe");
-      var zoom = geoScaleToZoom(projection2.scale());
-      var base = context.history().base();
-      function renderAsPoint(entity) {
-        return entity.geometry(graph) === "point" && !(zoom >= 18 && entity.directions(graph, projection2).length);
       }
-      var points = wireframe ? [] : entities.filter(renderAsPoint);
-      points.sort(sortY);
-      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.points");
-      var touchLayer = selection2.selectAll(".layer-touch.points");
-      var groups = drawLayer.selectAll("g.point").filter(filter2).data(points, fastEntityKey);
-      groups.exit().remove();
-      var enter = groups.enter().append("g").attr("class", function(d) {
-        return "node point " + d.id;
-      }).order();
-      enter.append("path").call(markerPath, "shadow");
-      enter.append("ellipse").attr("cx", 0.5).attr("cy", 1).attr("rx", 6.5).attr("ry", 3).attr("class", "stroke");
-      enter.append("path").call(markerPath, "stroke");
-      enter.append("use").attr("transform", "translate(-5.5, -20)").attr("class", "icon").attr("width", "12px").attr("height", "12px");
-      groups = groups.merge(enter).attr("transform", svgPointTransform(projection2)).classed("added", function(d) {
-        return !base.entities[d.id];
-      }).classed("moved", function(d) {
-        return base.entities[d.id] && !(0, import_fast_deep_equal7.default)(graph.entities[d.id].loc, base.entities[d.id].loc);
-      }).classed("retagged", function(d) {
-        return base.entities[d.id] && !(0, import_fast_deep_equal7.default)(graph.entities[d.id].tags, base.entities[d.id].tags);
-      }).call(svgTagClasses());
-      groups.select(".shadow");
-      groups.select(".stroke");
-      groups.select(".icon").attr("xlink:href", function(entity) {
-        var preset = _mainPresetIndex.match(entity, graph);
-        var picon = preset && preset.icon;
-        return picon ? "#" + picon : "";
-      });
-      touchLayer.call(drawTargets, graph, points, filter2);
-    }
-    return drawPoints;
-  }
-
-  // modules/svg/turns.js
-  function svgTurns(projection2, context) {
-    function icon2(turn) {
-      var u = turn.u ? "-u" : "";
-      if (turn.no)
-        return "#iD-turn-no" + u;
-      if (turn.only)
-        return "#iD-turn-only" + u;
-      return "#iD-turn-yes" + u;
-    }
-    function drawTurns(selection2, graph, turns) {
-      function turnTransform(d) {
-        var pxRadius = 50;
-        var toWay = graph.entity(d.to.way);
-        var toPoints = graph.childNodes(toWay).map(function(n2) {
-          return n2.loc;
-        }).map(projection2);
-        var toLength = geoPathLength(toPoints);
-        var mid = toLength / 2;
-        var toNode = graph.entity(d.to.node);
-        var toVertex = graph.entity(d.to.vertex);
-        var a = geoAngle(toVertex, toNode, projection2);
-        var o = projection2(toVertex.loc);
-        var r = d.u ? 0 : !toWay.__via ? pxRadius : Math.min(mid, pxRadius);
-        return "translate(" + (r * Math.cos(a) + o[0]) + "," + (r * Math.sin(a) + o[1]) + ") rotate(" + a * 180 / Math.PI + ")";
+      function pushPassive(start3, end2, index) {
+        features.passive.push({
+          type: "Feature",
+          id: way.id + "-" + index,
+          properties: {
+            target: true,
+            entity: way,
+            nodes: [start3.node, end2.node],
+            index
+          },
+          geometry: {
+            type: "LineString",
+            coordinates: [start3.node.loc, end2.node.loc]
+          }
+        });
       }
-      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.turns");
-      var touchLayer = selection2.selectAll(".layer-touch.turns");
-      var groups = drawLayer.selectAll("g.turn").data(turns, function(d) {
-        return d.key;
-      });
-      groups.exit().remove();
-      var groupsEnter = groups.enter().append("g").attr("class", function(d) {
-        return "turn " + d.key;
-      });
-      var turnsEnter = groupsEnter.filter(function(d) {
-        return !d.u;
-      });
-      turnsEnter.append("rect").attr("transform", "translate(-22, -12)").attr("width", "44").attr("height", "24");
-      turnsEnter.append("use").attr("transform", "translate(-22, -12)").attr("width", "44").attr("height", "24");
-      var uEnter = groupsEnter.filter(function(d) {
-        return d.u;
-      });
-      uEnter.append("circle").attr("r", "16");
-      uEnter.append("use").attr("transform", "translate(-16, -16)").attr("width", "32").attr("height", "32");
-      groups = groups.merge(groupsEnter).attr("opacity", function(d) {
-        return d.direct === false ? "0.7" : null;
-      }).attr("transform", turnTransform);
-      groups.select("use").attr("xlink:href", icon2);
-      groups.select("rect");
-      groups.select("circle");
-      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
-      groups = touchLayer.selectAll("g.turn").data(turns, function(d) {
-        return d.key;
-      });
-      groups.exit().remove();
-      groupsEnter = groups.enter().append("g").attr("class", function(d) {
-        return "turn " + d.key;
-      });
-      turnsEnter = groupsEnter.filter(function(d) {
-        return !d.u;
-      });
-      turnsEnter.append("rect").attr("class", "target " + fillClass).attr("transform", "translate(-22, -12)").attr("width", "44").attr("height", "24");
-      uEnter = groupsEnter.filter(function(d) {
-        return d.u;
-      });
-      uEnter.append("circle").attr("class", "target " + fillClass).attr("r", "16");
-      groups = groups.merge(groupsEnter).attr("transform", turnTransform);
-      groups.select("rect");
-      groups.select("circle");
-      return this;
     }
-    return drawTurns;
   }
 
-  // modules/svg/vertices.js
-  var import_fast_deep_equal8 = __toESM(require_fast_deep_equal());
-  function svgVertices(projection2, context) {
-    var radiuses = {
-      shadow: [6, 7.5, 7.5, 12],
-      stroke: [2.5, 3.5, 3.5, 8],
-      fill: [1, 1.5, 1.5, 1.5]
-    };
-    var _currHoverTarget;
-    var _currPersistent = {};
-    var _currHover = {};
-    var _prevHover = {};
-    var _currSelected = {};
-    var _prevSelected = {};
-    var _radii = {};
-    function sortY(a, b) {
-      return b.loc[1] - a.loc[1];
-    }
-    function fastEntityKey(d) {
-      var mode = context.mode();
-      var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
-      return isMoving ? d.id : osmEntity.key(d);
-    }
-    function draw(selection2, graph, vertices, sets2, filter2) {
-      sets2 = sets2 || { selected: {}, important: {}, hovered: {} };
-      var icons = {};
-      var directions = {};
-      var wireframe = context.surface().classed("fill-wireframe");
-      var zoom = geoScaleToZoom(projection2.scale());
-      var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
-      var activeID = context.activeID();
-      var base = context.history().base();
-      function getIcon(d) {
-        var entity = graph.entity(d.id);
-        if (entity.id in icons)
-          return icons[entity.id];
-        icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
-        return icons[entity.id];
-      }
-      function getDirections(entity) {
-        if (entity.id in directions)
-          return directions[entity.id];
-        var angles = entity.directions(graph, projection2);
-        directions[entity.id] = angles.length ? angles : false;
-        return angles;
+  // modules/svg/tag_classes.js
+  function svgTagClasses() {
+    var primaries = [
+      "building",
+      "highway",
+      "railway",
+      "waterway",
+      "aeroway",
+      "aerialway",
+      "piste:type",
+      "boundary",
+      "power",
+      "amenity",
+      "natural",
+      "landuse",
+      "leisure",
+      "military",
+      "place",
+      "man_made",
+      "route",
+      "attraction",
+      "roller_coaster",
+      "building:part",
+      "indoor"
+    ];
+    var statuses = Object.keys(osmLifecyclePrefixes);
+    var secondaries = [
+      "oneway",
+      "bridge",
+      "tunnel",
+      "embankment",
+      "cutting",
+      "barrier",
+      "surface",
+      "tracktype",
+      "footway",
+      "crossing",
+      "service",
+      "sport",
+      "public_transport",
+      "location",
+      "parking",
+      "golf",
+      "type",
+      "leisure",
+      "man_made",
+      "indoor",
+      "construction",
+      "proposed"
+    ];
+    var _tags = function(entity) {
+      return entity.tags;
+    };
+    var tagClasses = function(selection2) {
+      selection2.each(function tagClassesEach(entity) {
+        var value = this.className;
+        if (value.baseVal !== void 0) {
+          value = value.baseVal;
+        }
+        var t2 = _tags(entity);
+        var computed = tagClasses.getClassesString(t2, value);
+        if (computed !== value) {
+          select_default2(this).attr("class", computed);
+        }
+      });
+    };
+    tagClasses.getClassesString = function(t2, value) {
+      var primary, status;
+      var i3, j2, k2, v2;
+      var overrideGeometry;
+      if (/\bstroke\b/.test(value)) {
+        if (!!t2.barrier && t2.barrier !== "no") {
+          overrideGeometry = "line";
+        }
       }
-      function updateAttributes(selection3) {
-        ["shadow", "stroke", "fill"].forEach(function(klass) {
-          var rads = radiuses[klass];
-          selection3.selectAll("." + klass).each(function(entity) {
-            var i2 = z && getIcon(entity);
-            var r = rads[i2 ? 3 : z];
-            if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
-              r += 1.5;
+      var classes = value.trim().split(/\s+/).filter(function(klass) {
+        return klass.length && !/^tag-/.test(klass);
+      }).map(function(klass) {
+        return klass === "line" || klass === "area" ? overrideGeometry || klass : klass;
+      });
+      for (i3 = 0; i3 < primaries.length; i3++) {
+        k2 = primaries[i3];
+        v2 = t2[k2];
+        if (!v2 || v2 === "no") continue;
+        if (k2 === "piste:type") {
+          k2 = "piste";
+        } else if (k2 === "building:part") {
+          k2 = "building_part";
+        }
+        primary = k2;
+        if (statuses.indexOf(v2) !== -1) {
+          status = v2;
+          classes.push("tag-" + k2);
+        } else {
+          classes.push("tag-" + k2);
+          classes.push("tag-" + k2 + "-" + v2);
+        }
+        break;
+      }
+      if (!primary) {
+        for (i3 = 0; i3 < statuses.length; i3++) {
+          for (j2 = 0; j2 < primaries.length; j2++) {
+            k2 = statuses[i3] + ":" + primaries[j2];
+            v2 = t2[k2];
+            if (!v2 || v2 === "no") continue;
+            status = statuses[i3];
+            break;
+          }
+        }
+      }
+      if (!status) {
+        for (i3 = 0; i3 < statuses.length; i3++) {
+          k2 = statuses[i3];
+          v2 = t2[k2];
+          if (!v2 || v2 === "no") continue;
+          if (v2 === "yes") {
+            status = k2;
+          } else if (primary && primary === v2) {
+            status = k2;
+          } else if (!primary && primaries.indexOf(v2) !== -1) {
+            status = k2;
+            primary = v2;
+            classes.push("tag-" + v2);
+          }
+          if (status) break;
+        }
+      }
+      if (status) {
+        classes.push("tag-status");
+        classes.push("tag-status-" + status);
+      }
+      for (i3 = 0; i3 < secondaries.length; i3++) {
+        k2 = secondaries[i3];
+        v2 = t2[k2];
+        if (!v2 || v2 === "no" || k2 === primary) continue;
+        classes.push("tag-" + k2);
+        classes.push("tag-" + k2 + "-" + v2);
+      }
+      if (primary === "highway" && !osmPathHighwayTagValues[t2.highway] || primary === "aeroway") {
+        var surface = t2.highway === "track" ? "unpaved" : "paved";
+        for (k2 in t2) {
+          v2 = t2[k2];
+          if (k2 in osmPavedTags) {
+            surface = osmPavedTags[k2][v2] ? "paved" : "unpaved";
+          }
+          if (k2 in osmSemipavedTags && !!osmSemipavedTags[k2][v2]) {
+            surface = "semipaved";
+          }
+        }
+        classes.push("tag-" + surface);
+      }
+      var qid = t2.wikidata || t2["flag:wikidata"] || t2["brand:wikidata"] || t2["network:wikidata"] || t2["operator:wikidata"];
+      if (qid) {
+        classes.push("tag-wikidata");
+      }
+      return classes.filter((klass) => /^[-_a-z0-9]+$/.test(klass)).join(" ").trim();
+    };
+    tagClasses.tags = function(val) {
+      if (!arguments.length) return _tags;
+      _tags = val;
+      return tagClasses;
+    };
+    return tagClasses;
+  }
+
+  // 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"
+    },
+    landuse: {
+      cemetery: [
+        { religion: "christian", pattern: "cemetery_christian" },
+        { religion: "buddhist", pattern: "cemetery_buddhist" },
+        { religion: "muslim", pattern: "cemetery_muslim" },
+        { religion: "jewish", pattern: "cemetery_jewish" },
+        { pattern: "cemetery" }
+      ],
+      construction: "construction",
+      farmland: "farmland",
+      farmyard: "farmyard",
+      forest: [
+        { leaf_type: "broadleaved", pattern: "forest_broadleaved" },
+        { leaf_type: "needleleaved", pattern: "forest_needleleaved" },
+        { leaf_type: "leafless", pattern: "forest_leafless" },
+        { pattern: "forest" }
+        // same as 'leaf_type:mixed'
+      ],
+      grave_yard: "cemetery",
+      grass: "grass",
+      landfill: "landfill",
+      meadow: "meadow",
+      military: "construction",
+      orchard: "orchard",
+      quarry: "quarry",
+      vineyard: "vineyard"
+    },
+    leisure: {
+      horse_riding: "farmyard"
+    },
+    natural: {
+      beach: "beach",
+      grassland: "grass",
+      sand: "beach",
+      scrub: "scrub",
+      water: [
+        { water: "pond", pattern: "pond" },
+        { water: "reservoir", pattern: "water_standing" },
+        { pattern: "waves" }
+      ],
+      wetland: [
+        { wetland: "marsh", pattern: "wetland_marsh" },
+        { wetland: "swamp", pattern: "wetland_swamp" },
+        { wetland: "bog", pattern: "wetland_bog" },
+        { wetland: "reedbed", pattern: "wetland_reedbed" },
+        { pattern: "wetland" }
+      ],
+      wood: [
+        { leaf_type: "broadleaved", pattern: "forest_broadleaved" },
+        { leaf_type: "needleleaved", pattern: "forest_needleleaved" },
+        { leaf_type: "leafless", pattern: "forest_leafless" },
+        { pattern: "forest" }
+        // same as 'leaf_type:mixed'
+      ]
+    },
+    golf: {
+      green: "golf_green",
+      tee: "grass",
+      fairway: "grass",
+      rough: "scrub"
+    },
+    surface: {
+      grass: "grass",
+      sand: "beach"
+    }
+  };
+  function svgTagPattern(tags) {
+    if (tags.building && tags.building !== "no") {
+      return null;
+    }
+    for (var tag2 in patterns) {
+      var entityValue = tags[tag2];
+      if (!entityValue) continue;
+      if (typeof patterns[tag2] === "string") {
+        return "pattern-" + patterns[tag2];
+      } else {
+        var values = patterns[tag2];
+        for (var value in values) {
+          if (entityValue !== value) continue;
+          var rules = values[value];
+          if (typeof rules === "string") {
+            return "pattern-" + rules;
+          }
+          for (var ruleKey in rules) {
+            var rule = rules[ruleKey];
+            var pass = true;
+            for (var criterion in rule) {
+              if (criterion !== "pattern") {
+                var v2 = tags[criterion];
+                if (!v2 || v2 !== rule[criterion]) {
+                  pass = false;
+                  break;
+                }
+              }
             }
-            if (klass === "shadow") {
-              _radii[entity.id] = r;
+            if (pass) {
+              return "pattern-" + rule.pattern;
             }
-            select_default2(this).attr("r", r).attr("visibility", i2 && klass === "fill" ? "hidden" : null);
-          });
-        });
+          }
+        }
       }
-      vertices.sort(sortY);
-      var groups = selection2.selectAll("g.vertex").filter(filter2).data(vertices, fastEntityKey);
-      groups.exit().remove();
-      var enter = groups.enter().append("g").attr("class", function(d) {
-        return "node vertex " + d.id;
-      }).order();
-      enter.append("circle").attr("class", "shadow");
-      enter.append("circle").attr("class", "stroke");
-      enter.filter(function(d) {
-        return d.hasInterestingTags();
-      }).append("circle").attr("class", "fill");
-      groups = groups.merge(enter).attr("transform", svgPointTransform(projection2)).classed("sibling", function(d) {
-        return d.id in sets2.selected;
-      }).classed("shared", function(d) {
-        return graph.isShared(d);
-      }).classed("endpoint", function(d) {
-        return d.isEndpoint(graph);
-      }).classed("added", function(d) {
-        return !base.entities[d.id];
-      }).classed("moved", function(d) {
-        return base.entities[d.id] && !(0, import_fast_deep_equal8.default)(graph.entities[d.id].loc, base.entities[d.id].loc);
-      }).classed("retagged", function(d) {
-        return base.entities[d.id] && !(0, import_fast_deep_equal8.default)(graph.entities[d.id].tags, base.entities[d.id].tags);
-      }).call(updateAttributes);
-      var iconUse = groups.selectAll(".icon").data(function data(d) {
-        return zoom >= 17 && getIcon(d) ? [d] : [];
-      }, fastEntityKey);
-      iconUse.exit().remove();
-      iconUse.enter().append("use").attr("class", "icon").attr("width", "12px").attr("height", "12px").attr("transform", "translate(-6, -6)").attr("xlink:href", function(d) {
-        var picon = getIcon(d);
-        return picon ? "#" + picon : "";
-      });
-      var dgroups = groups.selectAll(".viewfieldgroup").data(function data(d) {
-        return zoom >= 18 && getDirections(d) ? [d] : [];
-      }, fastEntityKey);
-      dgroups.exit().remove();
-      dgroups = dgroups.enter().insert("g", ".shadow").attr("class", "viewfieldgroup").merge(dgroups);
-      var viewfields = dgroups.selectAll(".viewfield").data(getDirections, function key(d) {
-        return osmEntity.key(d);
-      });
-      viewfields.exit().remove();
-      viewfields.enter().append("path").attr("class", "viewfield").attr("d", "M0,0H0").merge(viewfields).attr("marker-start", "url(#ideditor-viewfield-marker" + (wireframe ? "-wireframe" : "") + ")").attr("transform", function(d) {
-        return "rotate(" + d + ")";
-      });
+    }
+    return null;
+  }
+
+  // modules/svg/areas.js
+  function svgAreas(projection2, context) {
+    function getPatternStyle(tags) {
+      var imageID = svgTagPattern(tags);
+      if (imageID) {
+        return 'url("#ideditor-' + imageID + '")';
+      }
+      return "";
     }
     function drawTargets(selection2, graph, entities, filter2) {
       var targetClass = context.getDebug("target") ? "pink " : "nocolor ";
       var nopeClass = context.getDebug("target") ? "red " : "nocolor ";
-      var getTransform = svgPointTransform(projection2).geojson;
+      var getPath = svgPath(projection2).geojson;
       var activeID = context.activeID();
+      var base = context.history().base();
       var data = { targets: [], nopes: [] };
-      entities.forEach(function(node) {
-        if (activeID === node.id)
-          return;
-        var vertexType = svgPassiveVertex(node, graph, activeID);
-        if (vertexType !== 0) {
-          data.targets.push({
-            type: "Feature",
-            id: node.id,
-            properties: {
-              target: true,
-              entity: node
-            },
-            geometry: node.asGeoJSON()
-          });
-        } else {
-          data.nopes.push({
-            type: "Feature",
-            id: node.id + "-nope",
-            properties: {
-              nope: true,
-              target: true,
-              entity: node
-            },
-            geometry: node.asGeoJSON()
-          });
-        }
+      entities.forEach(function(way) {
+        var features = svgSegmentWay(way, graph, activeID);
+        data.targets.push.apply(data.targets, features.passive);
+        data.nopes.push.apply(data.nopes, features.active);
       });
-      var targets = selection2.selectAll(".vertex.target-allowed").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(data.targets, function key(d) {
-        return d.id;
+      var targetData = data.targets.filter(getPath);
+      var targets = selection2.selectAll(".area.target-allowed").filter(function(d2) {
+        return filter2(d2.properties.entity);
+      }).data(targetData, function key(d2) {
+        return d2.id;
       });
       targets.exit().remove();
-      targets.enter().append("circle").attr("r", function(d) {
-        return _radii[d.id] || radiuses.shadow[3];
-      }).merge(targets).attr("class", function(d) {
-        return "node vertex target target-allowed " + targetClass + d.id;
-      }).attr("transform", getTransform);
-      var nopes = selection2.selectAll(".vertex.target-nope").filter(function(d) {
-        return filter2(d.properties.entity);
-      }).data(data.nopes, function key(d) {
-        return d.id;
-      });
-      nopes.exit().remove();
-      nopes.enter().append("circle").attr("r", function(d) {
-        return _radii[d.properties.entity.id] || radiuses.shadow[3];
-      }).merge(nopes).attr("class", function(d) {
-        return "node vertex target target-nope " + nopeClass + d.id;
-      }).attr("transform", getTransform);
-    }
-    function renderAsVertex(entity, graph, wireframe, zoom) {
-      var geometry = entity.geometry(graph);
-      return geometry === "vertex" || geometry === "point" && (wireframe || zoom >= 18 && entity.directions(graph, projection2).length);
-    }
-    function isEditedNode(node, base, head) {
-      var baseNode = base.entities[node.id];
-      var headNode = head.entities[node.id];
-      return !headNode || !baseNode || !(0, import_fast_deep_equal8.default)(headNode.tags, baseNode.tags) || !(0, import_fast_deep_equal8.default)(headNode.loc, baseNode.loc);
-    }
-    function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
-      var results = {};
-      var seenIds = {};
-      function addChildVertices(entity) {
-        if (seenIds[entity.id])
-          return;
-        seenIds[entity.id] = true;
-        var geometry = entity.geometry(graph);
-        if (!context.features().isHiddenFeature(entity, graph, geometry)) {
-          var i2;
-          if (entity.type === "way") {
-            for (i2 = 0; i2 < entity.nodes.length; i2++) {
-              var child = graph.hasEntity(entity.nodes[i2]);
-              if (child) {
-                addChildVertices(child);
-              }
-            }
-          } else if (entity.type === "relation") {
-            for (i2 = 0; i2 < entity.members.length; i2++) {
-              var member = graph.hasEntity(entity.members[i2].id);
-              if (member) {
-                addChildVertices(member);
-              }
-            }
-          } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
-            results[entity.id] = entity;
-          }
-        }
-      }
-      ids.forEach(function(id2) {
-        var entity = graph.hasEntity(id2);
-        if (!entity)
-          return;
-        if (entity.type === "node") {
-          if (renderAsVertex(entity, graph, wireframe, zoom)) {
-            results[entity.id] = entity;
-            graph.parentWays(entity).forEach(function(entity2) {
-              addChildVertices(entity2);
-            });
-          }
-        } else {
-          addChildVertices(entity);
+      var segmentWasEdited = function(d2) {
+        var wayID = d2.properties.entity.id;
+        if (!base.entities[wayID] || !(0, import_fast_deep_equal5.default)(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
+          return false;
         }
+        return d2.properties.nodes.some(function(n3) {
+          return !base.entities[n3.id] || !(0, import_fast_deep_equal5.default)(graph.entities[n3.id].loc, base.entities[n3.id].loc);
+        });
+      };
+      targets.enter().append("path").merge(targets).attr("d", getPath).attr("class", function(d2) {
+        return "way area target target-allowed " + targetClass + d2.id;
+      }).classed("segment-edited", segmentWasEdited);
+      var nopeData = data.nopes.filter(getPath);
+      var nopes = selection2.selectAll(".area.target-nope").filter(function(d2) {
+        return filter2(d2.properties.entity);
+      }).data(nopeData, function key(d2) {
+        return d2.id;
       });
-      return results;
+      nopes.exit().remove();
+      nopes.enter().append("path").merge(nopes).attr("d", getPath).attr("class", function(d2) {
+        return "way area target target-nope " + nopeClass + d2.id;
+      }).classed("segment-edited", segmentWasEdited);
     }
-    function drawVertices(selection2, graph, entities, filter2, extent, fullRedraw) {
-      var wireframe = context.surface().classed("fill-wireframe");
-      var visualDiff = context.surface().classed("highlight-edited");
-      var zoom = geoScaleToZoom(projection2.scale());
-      var mode = context.mode();
-      var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
+    function drawAreas(selection2, graph, entities, filter2) {
+      var path = svgPath(projection2, graph, true);
+      var areas = {};
       var base = context.history().base();
-      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.vertices");
-      var touchLayer = selection2.selectAll(".layer-touch.points");
-      if (fullRedraw) {
-        _currPersistent = {};
-        _radii = {};
-      }
-      for (var i2 = 0; i2 < entities.length; i2++) {
-        var entity = entities[i2];
-        var geometry = entity.geometry(graph);
-        var keep = false;
-        if (geometry === "point" && renderAsVertex(entity, graph, wireframe, zoom)) {
-          _currPersistent[entity.id] = entity;
-          keep = true;
-        } else if (geometry === "vertex" && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
-          _currPersistent[entity.id] = entity;
-          keep = true;
-        }
-        if (!keep && !fullRedraw) {
-          delete _currPersistent[entity.id];
+      for (var i3 = 0; i3 < entities.length; i3++) {
+        var entity = entities[i3];
+        if (entity.geometry(graph) !== "area") continue;
+        if (!areas[entity.id]) {
+          areas[entity.id] = {
+            entity,
+            area: Math.abs(entity.area(graph))
+          };
         }
       }
-      var sets2 = {
-        persistent: _currPersistent,
-        selected: _currSelected,
-        hovered: _currHover
-      };
-      var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent);
-      var filterRendered = function(d) {
-        return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter2(d);
-      };
-      drawLayer.call(draw, graph, currentVisible(all), sets2, filterRendered);
-      var filterTouch = function(d) {
-        return isMoving ? true : filterRendered(d);
+      var fills = Object.values(areas).filter(function hasPath(a2) {
+        return path(a2.entity);
+      });
+      fills.sort(function areaSort(a2, b2) {
+        return b2.area - a2.area;
+      });
+      fills = fills.map(function(a2) {
+        return a2.entity;
+      });
+      var strokes = fills.filter(function(area) {
+        return area.type === "way";
+      });
+      var data = {
+        clip: fills,
+        shadow: strokes,
+        stroke: strokes,
+        fill: fills
       };
-      touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
-      function currentVisible(which) {
-        return Object.keys(which).map(graph.hasEntity, graph).filter(function(entity2) {
-          return entity2 && entity2.intersects(extent, graph);
-        });
+      var clipPaths = context.surface().selectAll("defs").selectAll(".clipPath-osm").filter(filter2).data(data.clip, osmEntity.key);
+      clipPaths.exit().remove();
+      var clipPathsEnter = clipPaths.enter().append("clipPath").attr("class", "clipPath-osm").attr("id", function(entity2) {
+        return "ideditor-" + entity2.id + "-clippath";
+      });
+      clipPathsEnter.append("path");
+      clipPaths.merge(clipPathsEnter).selectAll("path").attr("d", path);
+      var drawLayer = selection2.selectAll(".layer-osm.areas");
+      var touchLayer = selection2.selectAll(".layer-touch.areas");
+      var areagroup = drawLayer.selectAll("g.areagroup").data(["fill", "shadow", "stroke"]);
+      areagroup = areagroup.enter().append("g").attr("class", function(d2) {
+        return "areagroup area-" + d2;
+      }).merge(areagroup);
+      var paths = areagroup.selectAll("path").filter(filter2).data(function(layer) {
+        return data[layer];
+      }, osmEntity.key);
+      paths.exit().remove();
+      var fillpaths = selection2.selectAll(".area-fill path.area").nodes();
+      var bisect = bisector(function(node) {
+        return -node.__data__.area(graph);
+      }).left;
+      function sortedByArea(entity2) {
+        if (this._parent.__data__ === "fill") {
+          return fillpaths[bisect(fillpaths, -entity2.area(graph))];
+        }
       }
+      paths = paths.enter().insert("path", sortedByArea).merge(paths).each(function(entity2) {
+        var layer = this.parentNode.__data__;
+        this.setAttribute("class", entity2.type + " area " + layer + " " + entity2.id);
+        if (layer === "fill") {
+          this.setAttribute("clip-path", "url(#ideditor-" + entity2.id + "-clippath)");
+          this.style.fill = this.style.stroke = getPatternStyle(entity2.tags);
+        }
+      }).classed("added", function(d2) {
+        return !base.entities[d2.id];
+      }).classed("geometry-edited", function(d2) {
+        return graph.entities[d2.id] && base.entities[d2.id] && !(0, import_fast_deep_equal5.default)(graph.entities[d2.id].nodes, base.entities[d2.id].nodes);
+      }).classed("retagged", function(d2) {
+        return graph.entities[d2.id] && base.entities[d2.id] && !(0, import_fast_deep_equal5.default)(graph.entities[d2.id].tags, base.entities[d2.id].tags);
+      }).call(svgTagClasses()).attr("d", path);
+      touchLayer.call(drawTargets, graph, data.stroke, filter2);
     }
-    drawVertices.drawSelected = function(selection2, graph, extent) {
-      var wireframe = context.surface().classed("fill-wireframe");
-      var zoom = geoScaleToZoom(projection2.scale());
-      _prevSelected = _currSelected || {};
-      if (context.map().isInWideSelection()) {
-        _currSelected = {};
-        context.selectedIDs().forEach(function(id2) {
-          var entity = graph.hasEntity(id2);
-          if (!entity)
-            return;
-          if (entity.type === "node") {
-            if (renderAsVertex(entity, graph, wireframe, zoom)) {
-              _currSelected[entity.id] = entity;
-            }
-          }
-        });
-      } else {
-        _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
-      }
-      var filter2 = function(d) {
-        return d.id in _prevSelected;
-      };
-      drawVertices(selection2, graph, Object.values(_prevSelected), filter2, extent, false);
-    };
-    drawVertices.drawHover = function(selection2, graph, target, extent) {
-      if (target === _currHoverTarget)
-        return;
-      var wireframe = context.surface().classed("fill-wireframe");
-      var zoom = geoScaleToZoom(projection2.scale());
-      _prevHover = _currHover || {};
-      _currHoverTarget = target;
-      var entity = target && target.properties && target.properties.entity;
-      if (entity) {
-        _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
-      } else {
-        _currHover = {};
-      }
-      var filter2 = function(d) {
-        return d.id in _prevHover;
-      };
-      drawVertices(selection2, graph, Object.values(_prevHover), filter2, extent, false);
-    };
-    return drawVertices;
+    return drawAreas;
   }
 
-  // modules/util/bind_once.js
-  function utilBindOnce(target, type3, listener, capture) {
-    var typeOnce = type3 + ".once";
-    function one2() {
-      target.on(typeOnce, null);
-      listener.apply(this, arguments);
-    }
-    target.on(typeOnce, one2, capture);
-    return this;
-  }
+  // modules/svg/data.js
+  var import_fast_json_stable_stringify = __toESM(require_fast_json_stable_stringify());
 
-  // modules/util/zoom_pan.js
-  function defaultFilter3(d3_event) {
-    return !d3_event.ctrlKey && !d3_event.button;
+  // node_modules/@tmcw/togeojson/dist/togeojson.es.mjs
+  function $(element, tagName) {
+    return Array.from(element.getElementsByTagName(tagName));
   }
-  function defaultExtent2() {
-    var e = this;
-    if (e instanceof SVGElement) {
-      e = e.ownerSVGElement || e;
-      if (e.hasAttribute("viewBox")) {
-        e = e.viewBox.baseVal;
-        return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
-      }
-      return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
-    }
-    return [[0, 0], [e.clientWidth, e.clientHeight]];
+  function normalizeId(id2) {
+    return id2[0] === "#" ? id2 : "#".concat(id2);
   }
-  function defaultWheelDelta2(d3_event) {
-    return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 2e-3);
+  function $ns(element, tagName, ns) {
+    return Array.from(element.getElementsByTagNameNS(ns, tagName));
   }
-  function defaultConstrain2(transform2, extent, translateExtent) {
-    var dx0 = transform2.invertX(extent[0][0]) - translateExtent[0][0], dx1 = transform2.invertX(extent[1][0]) - translateExtent[1][0], dy0 = transform2.invertY(extent[0][1]) - translateExtent[0][1], dy1 = transform2.invertY(extent[1][1]) - translateExtent[1][1];
-    return transform2.translate(
-      dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
-      dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
-    );
+  function nodeVal(node) {
+    node == null ? void 0 : node.normalize();
+    return node && node.textContent || "";
   }
-  function utilZoomPan() {
-    var filter2 = defaultFilter3, extent = defaultExtent2, constrain = defaultConstrain2, wheelDelta = defaultWheelDelta2, scaleExtent = [0, Infinity], translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], interpolate = zoom_default, dispatch10 = dispatch_default("start", "zoom", "end"), _wheelDelay = 150, _transform = identity2, _activeGesture;
-    function zoom(selection2) {
-      selection2.on("pointerdown.zoom", pointerdown).on("wheel.zoom", wheeled).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
-      select_default2(window).on("pointermove.zoompan", pointermove).on("pointerup.zoompan pointercancel.zoompan", pointerup);
+  function get1(node, tagName, callback) {
+    const n3 = node.getElementsByTagName(tagName);
+    const result = n3.length ? n3[0] : null;
+    if (result && callback)
+      callback(result);
+    return result;
+  }
+  function get3(node, tagName, callback) {
+    const properties = {};
+    if (!node)
+      return properties;
+    const n3 = node.getElementsByTagName(tagName);
+    const result = n3.length ? n3[0] : null;
+    if (result && callback) {
+      return callback(result, properties);
     }
-    zoom.transform = function(collection, transform2, point) {
-      var selection2 = collection.selection ? collection.selection() : collection;
-      if (collection !== selection2) {
-        schedule(collection, transform2, point);
-      } else {
-        selection2.interrupt().each(function() {
-          gesture(this, arguments).start(null).zoom(null, null, typeof transform2 === "function" ? transform2.apply(this, arguments) : transform2).end(null);
-        });
-      }
-    };
-    zoom.scaleBy = function(selection2, k, p) {
-      zoom.scaleTo(selection2, function() {
-        var k0 = _transform.k, k1 = typeof k === "function" ? k.apply(this, arguments) : k;
-        return k0 * k1;
-      }, p);
-    };
-    zoom.scaleTo = function(selection2, k, p) {
-      zoom.transform(selection2, function() {
-        var e = extent.apply(this, arguments), t0 = _transform, p02 = !p ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p, p1 = t0.invert(p02), k1 = typeof k === "function" ? k.apply(this, arguments) : k;
-        return constrain(translate(scale(t0, k1), p02, p1), e, translateExtent);
-      }, p);
-    };
-    zoom.translateBy = function(selection2, x, y) {
-      zoom.transform(selection2, function() {
-        return constrain(_transform.translate(
-          typeof x === "function" ? x.apply(this, arguments) : x,
-          typeof y === "function" ? y.apply(this, arguments) : y
-        ), extent.apply(this, arguments), translateExtent);
+    return properties;
+  }
+  function val1(node, tagName, callback) {
+    const val = nodeVal(get1(node, tagName));
+    if (val && callback)
+      return callback(val) || {};
+    return {};
+  }
+  function $num(node, tagName, callback) {
+    const val = parseFloat(nodeVal(get1(node, tagName)));
+    if (isNaN(val))
+      return void 0;
+    if (val && callback)
+      return callback(val) || {};
+    return {};
+  }
+  function num1(node, tagName, callback) {
+    const val = parseFloat(nodeVal(get1(node, tagName)));
+    if (isNaN(val))
+      return void 0;
+    if (callback)
+      callback(val);
+    return val;
+  }
+  function getMulti(node, propertyNames) {
+    const properties = {};
+    for (const property of propertyNames) {
+      val1(node, property, (val) => {
+        properties[property] = val;
       });
-    };
-    zoom.translateTo = function(selection2, x, y, p) {
-      zoom.transform(selection2, function() {
-        var e = extent.apply(this, arguments), t = _transform, p02 = !p ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
-        return constrain(identity2.translate(p02[0], p02[1]).scale(t.k).translate(
-          typeof x === "function" ? -x.apply(this, arguments) : -x,
-          typeof y === "function" ? -y.apply(this, arguments) : -y
-        ), e, translateExtent);
-      }, p);
-    };
-    function scale(transform2, k) {
-      k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
-      return k === transform2.k ? transform2 : new Transform(k, transform2.x, transform2.y);
-    }
-    function translate(transform2, p02, p1) {
-      var x = p02[0] - p1[0] * transform2.k, y = p02[1] - p1[1] * transform2.k;
-      return x === transform2.x && y === transform2.y ? transform2 : new Transform(transform2.k, x, y);
     }
-    function centroid(extent2) {
-      return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
+    return properties;
+  }
+  function isElement(node) {
+    return (node == null ? void 0 : node.nodeType) === 1;
+  }
+  function getLineStyle(node) {
+    return get3(node, "line", (lineStyle) => {
+      const val = Object.assign({}, val1(lineStyle, "color", (color2) => {
+        return { stroke: "#".concat(color2) };
+      }), $num(lineStyle, "opacity", (opacity) => {
+        return { "stroke-opacity": opacity };
+      }), $num(lineStyle, "width", (width) => {
+        return { "stroke-width": width * 96 / 25.4 };
+      }));
+      return val;
+    });
+  }
+  function getExtensions(node) {
+    let values = [];
+    if (node === null)
+      return values;
+    for (const child of Array.from(node.childNodes)) {
+      if (!isElement(child))
+        continue;
+      const name = abbreviateName(child.nodeName);
+      if (name === "gpxtpx:TrackPointExtension") {
+        values = values.concat(getExtensions(child));
+      } else {
+        const val = nodeVal(child);
+        values.push([name, parseNumeric(val)]);
+      }
     }
-    function schedule(transition2, transform2, point) {
-      transition2.on("start.zoom", function() {
-        gesture(this, arguments).start(null);
-      }).on("interrupt.zoom end.zoom", function() {
-        gesture(this, arguments).end(null);
-      }).tween("zoom", function() {
-        var that = this, args = arguments, 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));
-        return function(t) {
-          if (t === 1) {
-            t = b;
-          } else {
-            var l = i2(t);
-            var k = w / l[2];
-            t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
-          }
-          g.zoom(null, null, t);
-        };
-      });
+    return values;
+  }
+  function abbreviateName(name) {
+    return ["heart", "gpxtpx:hr", "hr"].includes(name) ? "heart" : name;
+  }
+  function parseNumeric(val) {
+    const num = parseFloat(val);
+    return isNaN(num) ? val : num;
+  }
+  function coordPair$1(node) {
+    const ll = [
+      parseFloat(node.getAttribute("lon") || ""),
+      parseFloat(node.getAttribute("lat") || "")
+    ];
+    if (isNaN(ll[0]) || isNaN(ll[1])) {
+      return null;
     }
-    function gesture(that, args, clean2) {
-      return !clean2 && _activeGesture || new Gesture(that, args);
+    num1(node, "ele", (val) => {
+      ll.push(val);
+    });
+    const time = get1(node, "time");
+    return {
+      coordinates: ll,
+      time: time ? nodeVal(time) : null,
+      extendedValues: getExtensions(get1(node, "extensions"))
+    };
+  }
+  function extractProperties(node) {
+    var _a3;
+    const properties = getMulti(node, [
+      "name",
+      "cmt",
+      "desc",
+      "type",
+      "time",
+      "keywords"
+    ]);
+    const extensions = Array.from(node.getElementsByTagNameNS("http://www.garmin.com/xmlschemas/GpxExtensions/v3", "*"));
+    for (const child of extensions) {
+      if (((_a3 = child.parentNode) == null ? void 0 : _a3.parentNode) === node) {
+        properties[child.tagName.replace(":", "_")] = nodeVal(child);
+      }
     }
-    function Gesture(that, args) {
-      this.that = that;
-      this.args = args;
-      this.active = 0;
-      this.extent = extent.apply(that, args);
+    const links = $(node, "link");
+    if (links.length) {
+      properties.links = links.map((link3) => Object.assign({ href: link3.getAttribute("href") }, getMulti(link3, ["text", "type"])));
     }
-    Gesture.prototype = {
-      start: function(d3_event) {
-        if (++this.active === 1) {
-          _activeGesture = this;
-          dispatch10.call("start", this, d3_event);
-        }
-        return this;
-      },
-      zoom: function(d3_event, key, transform2) {
-        if (this.mouse && key !== "mouse")
-          this.mouse[1] = transform2.invert(this.mouse[0]);
-        if (this.pointer0 && key !== "touch")
-          this.pointer0[1] = transform2.invert(this.pointer0[0]);
-        if (this.pointer1 && key !== "touch")
-          this.pointer1[1] = transform2.invert(this.pointer1[0]);
-        _transform = transform2;
-        dispatch10.call("zoom", this, d3_event, key, transform2);
-        return this;
-      },
-      end: function(d3_event) {
-        if (--this.active === 0) {
-          _activeGesture = null;
-          dispatch10.call("end", this, d3_event);
-        }
-        return this;
+    return properties;
+  }
+  function getPoints$1(node, pointname) {
+    const pts = $(node, pointname);
+    const line = [];
+    const times = [];
+    const extendedValues = {};
+    for (let i3 = 0; i3 < pts.length; i3++) {
+      const c2 = coordPair$1(pts[i3]);
+      if (!c2) {
+        continue;
       }
-    };
-    function wheeled(d3_event) {
-      if (!filter2.apply(this, arguments))
-        return;
-      var g = gesture(this, arguments), t = _transform, k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p = utilFastMouse(this)(d3_event);
-      if (g.wheel) {
-        if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
-          g.mouse[1] = t.invert(g.mouse[0] = p);
+      line.push(c2.coordinates);
+      if (c2.time)
+        times.push(c2.time);
+      for (const [name, val] of c2.extendedValues) {
+        const plural = name === "heart" ? name : name.replace("gpxtpx:", "") + "s";
+        if (!extendedValues[plural]) {
+          extendedValues[plural] = Array(pts.length).fill(null);
         }
-        clearTimeout(g.wheel);
-      } else {
-        g.mouse = [p, t.invert(p)];
-        interrupt_default(this);
-        g.start(d3_event);
-      }
-      d3_event.preventDefault();
-      d3_event.stopImmediatePropagation();
-      g.wheel = setTimeout(wheelidled, _wheelDelay);
-      g.zoom(d3_event, "mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
-      function wheelidled() {
-        g.wheel = null;
-        g.end(d3_event);
+        extendedValues[plural][i3] = val;
       }
     }
-    var _downPointerIDs = /* @__PURE__ */ new Set();
-    var _pointerLocGetter;
-    function pointerdown(d3_event) {
-      _downPointerIDs.add(d3_event.pointerId);
-      if (!filter2.apply(this, arguments))
-        return;
-      var g = gesture(this, arguments, _downPointerIDs.size === 1);
-      var started;
-      d3_event.stopImmediatePropagation();
-      _pointerLocGetter = utilFastMouse(this);
-      var loc = _pointerLocGetter(d3_event);
-      var p = [loc, _transform.invert(loc), d3_event.pointerId];
-      if (!g.pointer0) {
-        g.pointer0 = p;
-        started = true;
-      } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
-        g.pointer1 = p;
+    if (line.length < 2)
+      return;
+    return {
+      line,
+      times,
+      extendedValues
+    };
+  }
+  function getRoute(node) {
+    const line = getPoints$1(node, "rtept");
+    if (!line)
+      return;
+    return {
+      type: "Feature",
+      properties: Object.assign({ _gpxType: "rte" }, extractProperties(node), getLineStyle(get1(node, "extensions"))),
+      geometry: {
+        type: "LineString",
+        coordinates: line.line
       }
-      if (started) {
-        interrupt_default(this);
-        g.start(d3_event);
+    };
+  }
+  function getTrack(node) {
+    const segments = $(node, "trkseg");
+    const track = [];
+    const times = [];
+    const extractedLines = [];
+    for (const segment of segments) {
+      const line = getPoints$1(segment, "trkpt");
+      if (line) {
+        extractedLines.push(line);
+        if (line.times && line.times.length)
+          times.push(line.times);
       }
     }
-    function pointermove(d3_event) {
-      if (!_downPointerIDs.has(d3_event.pointerId))
-        return;
-      if (!_activeGesture || !_pointerLocGetter)
-        return;
-      var g = gesture(this, arguments);
-      var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
-      var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
-      if ((isPointer0 || isPointer1) && "buttons" in d3_event && !d3_event.buttons) {
-        if (g.pointer0)
-          _downPointerIDs.delete(g.pointer0[2]);
-        if (g.pointer1)
-          _downPointerIDs.delete(g.pointer1[2]);
-        g.end(d3_event);
-        return;
+    if (extractedLines.length === 0)
+      return null;
+    const multi = extractedLines.length > 1;
+    const properties = Object.assign({ _gpxType: "trk" }, extractProperties(node), getLineStyle(get1(node, "extensions")), times.length ? {
+      coordinateProperties: {
+        times: multi ? times : times[0]
       }
-      d3_event.preventDefault();
-      d3_event.stopImmediatePropagation();
-      var loc = _pointerLocGetter(d3_event);
-      var t, p, l;
-      if (isPointer0)
-        g.pointer0[0] = loc;
-      else if (isPointer1)
-        g.pointer1[0] = loc;
-      t = _transform;
-      if (g.pointer1) {
-        var p02 = g.pointer0[0], l0 = g.pointer0[1], p1 = g.pointer1[0], l1 = g.pointer1[1], dp = (dp = p1[0] - p02[0]) * dp + (dp = p1[1] - p02[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
-        t = scale(t, Math.sqrt(dp / dl));
-        p = [(p02[0] + p1[0]) / 2, (p02[1] + p1[1]) / 2];
-        l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
-      } else if (g.pointer0) {
-        p = g.pointer0[0];
-        l = g.pointer0[1];
-      } else {
-        return;
+    } : {});
+    for (const line of extractedLines) {
+      track.push(line.line);
+      if (!properties.coordinateProperties) {
+        properties.coordinateProperties = {};
       }
-      g.zoom(d3_event, "touch", constrain(translate(t, p, l), g.extent, translateExtent));
-    }
-    function pointerup(d3_event) {
-      if (!_downPointerIDs.has(d3_event.pointerId))
-        return;
-      _downPointerIDs.delete(d3_event.pointerId);
-      if (!_activeGesture)
-        return;
-      var g = gesture(this, arguments);
-      d3_event.stopImmediatePropagation();
-      if (g.pointer0 && g.pointer0[2] === d3_event.pointerId)
-        delete g.pointer0;
-      else if (g.pointer1 && g.pointer1[2] === d3_event.pointerId)
-        delete g.pointer1;
-      if (g.pointer1 && !g.pointer0) {
-        g.pointer0 = g.pointer1;
-        delete g.pointer1;
-      }
-      if (g.pointer0) {
-        g.pointer0[1] = _transform.invert(g.pointer0[0]);
-      } else {
-        g.end(d3_event);
+      const props = properties.coordinateProperties;
+      const entries = Object.entries(line.extendedValues);
+      for (let i3 = 0; i3 < entries.length; i3++) {
+        const [name, val] = entries[i3];
+        if (multi) {
+          if (!props[name]) {
+            props[name] = extractedLines.map((line2) => new Array(line2.line.length).fill(null));
+          }
+          props[name][i3] = val;
+        } else {
+          props[name] = val;
+        }
       }
     }
-    zoom.wheelDelta = function(_) {
-      return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
-    };
-    zoom.filter = function(_) {
-      return arguments.length ? (filter2 = utilFunctor(!!_), zoom) : filter2;
-    };
-    zoom.extent = function(_) {
-      return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
-    };
-    zoom.scaleExtent = function(_) {
-      return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
-    };
-    zoom.translateExtent = function(_) {
-      return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
-    };
-    zoom.constrain = function(_) {
-      return arguments.length ? (constrain = _, zoom) : constrain;
+    return {
+      type: "Feature",
+      properties,
+      geometry: multi ? {
+        type: "MultiLineString",
+        coordinates: track
+      } : {
+        type: "LineString",
+        coordinates: track[0]
+      }
     };
-    zoom.interpolate = function(_) {
-      return arguments.length ? (interpolate = _, zoom) : interpolate;
+  }
+  function getPoint(node) {
+    const properties = Object.assign(extractProperties(node), getMulti(node, ["sym"]));
+    const pair3 = coordPair$1(node);
+    if (!pair3)
+      return null;
+    return {
+      type: "Feature",
+      properties,
+      geometry: {
+        type: "Point",
+        coordinates: pair3.coordinates
+      }
     };
-    zoom._transform = function(_) {
-      return arguments.length ? (_transform = _, zoom) : _transform;
+  }
+  function* gpxGen(node) {
+    for (const track of $(node, "trk")) {
+      const feature3 = getTrack(track);
+      if (feature3)
+        yield feature3;
+    }
+    for (const route of $(node, "rte")) {
+      const feature3 = getRoute(route);
+      if (feature3)
+        yield feature3;
+    }
+    for (const waypoint of $(node, "wpt")) {
+      const point = getPoint(waypoint);
+      if (point)
+        yield point;
+    }
+  }
+  function gpx(node) {
+    return {
+      type: "FeatureCollection",
+      features: Array.from(gpxGen(node))
     };
-    return utilRebind(zoom, dispatch10, "on");
   }
-
-  // modules/util/double_up.js
-  function utilDoubleUp() {
-    var dispatch10 = dispatch_default("doubleUp");
-    var _maxTimespan = 500;
-    var _maxDistance = 20;
-    var _pointer;
-    function pointerIsValidFor(loc) {
-      return new Date().getTime() - _pointer.startTime <= _maxTimespan && geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
+  function fixColor(v2, prefix) {
+    const properties = {};
+    const colorProp = prefix == "stroke" || prefix === "fill" ? prefix : prefix + "-color";
+    if (v2[0] === "#") {
+      v2 = v2.substring(1);
     }
-    function pointerdown(d3_event) {
-      if (d3_event.ctrlKey || d3_event.button === 2)
-        return;
-      var loc = [d3_event.clientX, d3_event.clientY];
-      if (_pointer && !pointerIsValidFor(loc)) {
-        _pointer = void 0;
+    if (v2.length === 6 || v2.length === 3) {
+      properties[colorProp] = "#" + v2;
+    } else if (v2.length === 8) {
+      properties[prefix + "-opacity"] = parseInt(v2.substring(0, 2), 16) / 255;
+      properties[colorProp] = "#" + v2.substring(6, 8) + v2.substring(4, 6) + v2.substring(2, 4);
+    }
+    return properties;
+  }
+  function numericProperty(node, source, target) {
+    const properties = {};
+    num1(node, source, (val) => {
+      properties[target] = val;
+    });
+    return properties;
+  }
+  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) => {
+        const left = parseFloat(hotspot.getAttribute("x") || "");
+        const top = parseFloat(hotspot.getAttribute("y") || "");
+        const xunits = hotspot.getAttribute("xunits") || "";
+        const yunits = hotspot.getAttribute("yunits") || "";
+        if (!isNaN(left) && !isNaN(top))
+          return {
+            "icon-offset": [left, top],
+            "icon-offset-units": [xunits, yunits]
+          };
+        return {};
+      }), extractIconHref(iconStyle));
+    });
+  }
+  function extractLabel(node) {
+    return get3(node, "LabelStyle", (labelStyle) => {
+      return Object.assign(getColor(labelStyle, "label"), numericProperty(labelStyle, "scale", "label-scale"));
+    });
+  }
+  function extractLine(node) {
+    return get3(node, "LineStyle", (lineStyle) => {
+      return Object.assign(getColor(lineStyle, "stroke"), numericProperty(lineStyle, "width", "stroke-width"));
+    });
+  }
+  function extractPoly(node) {
+    return get3(node, "PolyStyle", (polyStyle, properties) => {
+      return Object.assign(properties, get3(polyStyle, "color", (elem) => fixColor(nodeVal(elem), "fill")), val1(polyStyle, "fill", (fill) => {
+        if (fill === "0")
+          return { "fill-opacity": 0 };
+      }), val1(polyStyle, "outline", (outline) => {
+        if (outline === "0")
+          return { "stroke-opacity": 0 };
+      }));
+    });
+  }
+  function extractStyle(node) {
+    return Object.assign({}, extractPoly(node), extractLine(node), extractLabel(node), extractIcon(node));
+  }
+  var toNumber2 = (x2) => Number(x2);
+  var typeConverters = {
+    string: (x2) => x2,
+    int: toNumber2,
+    uint: toNumber2,
+    short: toNumber2,
+    ushort: toNumber2,
+    float: toNumber2,
+    double: toNumber2,
+    bool: (x2) => Boolean(x2)
+  };
+  function extractExtendedData(node, schema) {
+    return get3(node, "ExtendedData", (extendedData, properties) => {
+      for (const data of $(extendedData, "Data")) {
+        properties[data.getAttribute("name") || ""] = nodeVal(get1(data, "value"));
       }
-      if (!_pointer) {
-        _pointer = {
-          startLoc: loc,
-          startTime: new Date().getTime(),
-          upCount: 0,
-          pointerId: d3_event.pointerId
+      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 c2 of Array.from((descriptionNode == null ? void 0 : descriptionNode.childNodes) || [])) {
+      if (c2.nodeType === 4) {
+        return {
+          description: {
+            "@type": "html",
+            value: nodeVal(c2)
+          }
         };
-      } else {
-        _pointer.pointerId = d3_event.pointerId;
       }
     }
-    function pointerup(d3_event) {
-      if (d3_event.ctrlKey || d3_event.button === 2)
-        return;
-      if (!_pointer || _pointer.pointerId !== d3_event.pointerId)
-        return;
-      _pointer.upCount += 1;
-      if (_pointer.upCount === 2) {
-        var loc = [d3_event.clientX, d3_event.clientY];
-        if (pointerIsValidFor(loc)) {
-          var locInThis = utilFastMouse(this)(d3_event);
-          dispatch10.call("doubleUp", this, d3_event, locInThis);
+    return {};
+  }
+  function extractTimeSpan(node) {
+    return get3(node, "TimeSpan", (timeSpan) => {
+      return {
+        timespan: {
+          begin: nodeVal(get1(timeSpan, "begin")),
+          end: nodeVal(get1(timeSpan, "end"))
         }
-        _pointer = void 0;
+      };
+    });
+  }
+  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+/;
+  function coord1(value) {
+    return value.replace(removeSpace, "").split(",").map(parseFloat).filter((num) => !isNaN(num)).slice(0, 3);
+  }
+  function coord(value) {
+    return value.replace(trimSpace, "").split(splitSpace).map(coord1).filter((coord2) => {
+      return coord2.length >= 2;
+    });
+  }
+  function gxCoords(node) {
+    let elems = $(node, "coord");
+    if (elems.length === 0) {
+      elems = $ns(node, "coord", "*");
     }
-    function doubleUp(selection2) {
-      if ("PointerEvent" in window) {
-        selection2.on("pointerdown.doubleUp", pointerdown).on("pointerup.doubleUp", pointerup);
-      } else {
-        selection2.on("dblclick.doubleUp", function(d3_event) {
-          dispatch10.call("doubleUp", this, d3_event, utilFastMouse(this)(d3_event));
-        });
-      }
+    const coordinates = elems.map((elem) => {
+      return nodeVal(elem).split(" ").map(parseFloat);
+    });
+    if (coordinates.length === 0) {
+      return null;
     }
-    doubleUp.off = function(selection2) {
-      selection2.on("pointerdown.doubleUp", null).on("pointerup.doubleUp", null).on("dblclick.doubleUp", null);
+    return {
+      geometry: coordinates.length > 2 ? {
+        type: "LineString",
+        coordinates
+      } : {
+        type: "Point",
+        coordinates: coordinates[0]
+      },
+      times: $(node, "when").map((elem) => nodeVal(elem))
     };
-    return utilRebind(doubleUp, dispatch10, "on");
   }
-
-  // modules/renderer/map.js
-  var TILESIZE = 256;
-  var minZoom2 = 2;
-  var maxZoom = 24;
-  var kMin = geoZoomToScale(minZoom2, TILESIZE);
-  var kMax = geoZoomToScale(maxZoom, TILESIZE);
-  function clamp(num, min3, max3) {
-    return Math.max(min3, Math.min(num, max3));
+  function fixRing(ring) {
+    if (ring.length === 0)
+      return ring;
+    const first = ring[0];
+    const last = ring[ring.length - 1];
+    let equal = true;
+    for (let i3 = 0; i3 < Math.max(first.length, last.length); i3++) {
+      if (first[i3] !== last[i3]) {
+        equal = false;
+        break;
+      }
+    }
+    if (!equal) {
+      return ring.concat([ring[0]]);
+    }
+    return ring;
   }
-  function rendererMap(context) {
-    var dispatch10 = dispatch_default(
-      "move",
-      "drawn",
-      "crossEditableZoom",
-      "hitMinZoom",
-      "changeHighlighting",
-      "changeAreaFill"
-    );
-    var projection2 = context.projection;
-    var curtainProjection = context.curtainProjection;
-    var drawLayers;
-    var drawPoints;
-    var drawVertices;
-    var drawLines;
-    var drawAreas;
-    var drawMidpoints;
-    var drawLabels;
-    var _selection = select_default2(null);
-    var supersurface = select_default2(null);
-    var wrapper = select_default2(null);
-    var surface = select_default2(null);
-    var _dimensions = [1, 1];
-    var _dblClickZoomEnabled = true;
-    var _redrawEnabled = true;
-    var _gestureTransformStart;
-    var _transformStart = projection2.transform();
-    var _transformLast;
-    var _isTransformed = false;
-    var _minzoom = 0;
-    var _getMouseCoords;
-    var _lastPointerEvent;
-    var _lastWithinEditableZoom;
-    var _pointerDown = false;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    var _zoomerPannerFunction = "PointerEvent" in window ? utilZoomPan : zoom_default2;
-    var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(value_default).filter(zoomEventFilter).on("zoom.map", zoomPan).on("start.map", function(d3_event) {
-      _pointerDown = d3_event && (d3_event.type === "pointerdown" || d3_event.sourceEvent && d3_event.sourceEvent.type === "pointerdown");
-    }).on("end.map", function() {
-      _pointerDown = false;
-    });
-    var _doubleUpHandler = utilDoubleUp();
-    var scheduleRedraw = throttle_default(redraw, 750);
-    function cancelPendingRedraw() {
-      scheduleRedraw.cancel();
-    }
-    function map2(selection2) {
-      _selection = selection2;
-      context.on("change.map", immediateRedraw);
-      var osm = context.connection();
-      if (osm) {
-        osm.on("change.map", immediateRedraw);
-      }
-      function didUndoOrRedo(targetTransform) {
-        var mode = context.mode().id;
-        if (mode !== "browse" && mode !== "select")
-          return;
-        if (targetTransform) {
-          map2.transformEase(targetTransform);
-        }
-      }
-      context.history().on("merge.map", function() {
-        scheduleRedraw();
-      }).on("change.map", immediateRedraw).on("undone.map", function(stack, fromStack) {
-        didUndoOrRedo(fromStack.transform);
-      }).on("redone.map", function(stack) {
-        didUndoOrRedo(stack.transform);
-      });
-      context.background().on("change.map", immediateRedraw);
-      context.features().on("redraw.map", immediateRedraw);
-      drawLayers.on("change.map", function() {
-        context.background().updateImagery();
-        immediateRedraw();
-      });
-      selection2.on("wheel.map mousewheel.map", function(d3_event) {
-        d3_event.preventDefault();
-      }).call(_zoomerPanner).call(_zoomerPanner.transform, projection2.transform()).on("dblclick.zoom", null);
-      map2.supersurface = supersurface = selection2.append("div").attr("class", "supersurface").call(utilSetTransform, 0, 0);
-      wrapper = supersurface.append("div").attr("class", "layer layer-data");
-      map2.surface = surface = wrapper.call(drawLayers).selectAll(".surface");
-      surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + "down.zoom", function(d3_event) {
-        _lastPointerEvent = d3_event;
-        if (d3_event.button === 2) {
-          d3_event.stopPropagation();
-        }
-      }, true).on(_pointerPrefix + "up.zoom", function(d3_event) {
-        _lastPointerEvent = d3_event;
-        if (resetTransform()) {
-          immediateRedraw();
-        }
-      }).on(_pointerPrefix + "move.map", function(d3_event) {
-        _lastPointerEvent = d3_event;
-      }).on(_pointerPrefix + "over.vertices", function(d3_event) {
-        if (map2.editableDataEnabled() && !_isTransformed) {
-          var hover = d3_event.target.__data__;
-          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
-          dispatch10.call("drawn", this, { full: false });
-        }
-      }).on(_pointerPrefix + "out.vertices", function(d3_event) {
-        if (map2.editableDataEnabled() && !_isTransformed) {
-          var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
-          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
-          dispatch10.call("drawn", this, { full: false });
-        }
-      });
-      var detected = utilDetect();
-      if ("GestureEvent" in window && !detected.isMobileWebKit) {
-        surface.on("gesturestart.surface", function(d3_event) {
-          d3_event.preventDefault();
-          _gestureTransformStart = projection2.transform();
-        }).on("gesturechange.surface", gestureChange);
-      }
-      updateAreaFill();
-      _doubleUpHandler.on("doubleUp.map", function(d3_event, p02) {
-        if (!_dblClickZoomEnabled)
-          return;
-        if (typeof d3_event.target.__data__ === "object" && !select_default2(d3_event.target).classed("fill"))
-          return;
-        var zoomOut2 = d3_event.shiftKey;
-        var t = projection2.transform();
-        var p1 = t.invert(p02);
-        t = t.scale(zoomOut2 ? 0.5 : 2);
-        t.x = p02[0] - p1[0] * t.k;
-        t.y = p02[1] - p1[1] * t.k;
-        map2.transformEase(t);
-      });
-      context.on("enter.map", function() {
-        if (!map2.editableDataEnabled(true))
-          return;
-        if (_isTransformed)
-          return;
-        var graph = context.graph();
-        var selectedAndParents = {};
-        context.selectedIDs().forEach(function(id2) {
-          var entity = graph.hasEntity(id2);
-          if (entity) {
-            selectedAndParents[entity.id] = entity;
-            if (entity.type === "node") {
-              graph.parentWays(entity).forEach(function(parent) {
-                selectedAndParents[parent.id] = parent;
+  function getCoordinates(node) {
+    return nodeVal(get1(node, "coordinates"));
+  }
+  function getGeometry(node) {
+    let geometries = [];
+    let coordTimes = [];
+    for (let i3 = 0; i3 < node.childNodes.length; i3++) {
+      const child = node.childNodes.item(i3);
+      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(child));
+            if (coordinates.length >= 2) {
+              geometries.push({
+                type: "Point",
+                coordinates
               });
             }
+            break;
           }
-        });
-        var data = Object.values(selectedAndParents);
-        var filter2 = function(d) {
-          return d.id in selectedAndParents;
-        };
-        data = context.features().filter(data, graph);
-        surface.call(drawVertices.drawSelected, graph, map2.extent()).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent());
-        dispatch10.call("drawn", this, { full: false });
-        scheduleRedraw();
-      });
-      map2.dimensions(utilGetDimensions(selection2));
-    }
-    function zoomEventFilter(d3_event) {
-      if (d3_event.type === "mousedown") {
-        var hasOrphan = false;
-        var listeners = window.__on;
-        for (var i2 = 0; i2 < listeners.length; i2++) {
-          var listener = listeners[i2];
-          if (listener.name === "zoom" && listener.type === "mouseup") {
-            hasOrphan = true;
+          case "LinearRing":
+          case "LineString": {
+            const coordinates = coord(getCoordinates(child));
+            if (coordinates.length >= 2) {
+              geometries.push({
+                type: "LineString",
+                coordinates
+              });
+            }
             break;
           }
-        }
-        if (hasOrphan) {
-          var event = window.CustomEvent;
-          if (event) {
-            event = new event("mouseup");
-          } else {
-            event = window.document.createEvent("Event");
-            event.initEvent("mouseup", false, false);
+          case "Polygon": {
+            const coords = [];
+            for (const linearRing of $(child, "LinearRing")) {
+              const ring = fixRing(coord(getCoordinates(linearRing)));
+              if (ring.length >= 4) {
+                coords.push(ring);
+              }
+            }
+            if (coords.length) {
+              geometries.push({
+                type: "Polygon",
+                coordinates: coords
+              });
+            }
+            break;
+          }
+          case "Track":
+          case "gx:Track": {
+            const gx = gxCoords(child);
+            if (!gx)
+              break;
+            const { times, geometry } = gx;
+            geometries.push(geometry);
+            if (times.length)
+              coordTimes.push(times);
+            break;
           }
-          event.view = window;
-          window.dispatchEvent(event);
         }
       }
-      return d3_event.button !== 2;
     }
-    function pxCenter() {
-      return [_dimensions[0] / 2, _dimensions[1] / 2];
+    return {
+      geometries,
+      coordTimes
+    };
+  }
+  function geometryListToGeometry(geometries) {
+    return geometries.length === 0 ? null : geometries.length === 1 ? geometries[0] : {
+      type: "GeometryCollection",
+      geometries
+    };
+  }
+  function getPlacemark(node, styleMap, schema, options2) {
+    var _a3;
+    const { coordTimes, geometries } = getGeometry(node);
+    const geometry = geometryListToGeometry(geometries);
+    if (!geometry && options2.skipNullGeometry) {
+      return null;
     }
-    function drawEditable(difference, extent) {
-      var mode = context.mode();
-      var graph = context.graph();
-      var features2 = context.features();
-      var all = context.history().intersects(map2.extent());
-      var fullRedraw = false;
-      var data;
-      var set3;
-      var filter2;
-      var applyFeatureLayerFilters = true;
-      if (map2.isInWideSelection()) {
-        data = [];
-        utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function(id2) {
-          var entity = context.hasEntity(id2);
-          if (entity)
-            data.push(entity);
-        });
-        fullRedraw = true;
-        filter2 = utilFunctor(true);
-        applyFeatureLayerFilters = false;
-      } else if (difference) {
-        var complete = difference.complete(map2.extent());
-        data = Object.values(complete).filter(Boolean);
-        set3 = new Set(Object.keys(complete));
-        filter2 = function(d) {
-          return set3.has(d.id);
-        };
-        features2.clear(data);
-      } else {
-        if (features2.gatherStats(all, graph, _dimensions)) {
-          extent = void 0;
-        }
-        if (extent) {
-          data = context.history().intersects(map2.extent().intersection(extent));
-          set3 = new Set(data.map(function(entity) {
-            return entity.id;
-          }));
-          filter2 = function(d) {
-            return set3.has(d.id);
-          };
-        } else {
-          data = all;
-          fullRedraw = true;
-          filter2 = utilFunctor(true);
+    const feature3 = {
+      type: "Feature",
+      geometry,
+      properties: Object.assign(getMulti(node, [
+        "name",
+        "address",
+        "visibility",
+        "open",
+        "phoneNumber",
+        "description"
+      ]), getMaybeHTMLDescription(node), extractCascadedStyle(node, styleMap), extractStyle(node), extractExtendedData(node, schema), extractTimeSpan(node), extractTimeStamp(node), coordTimes.length ? {
+        coordinateProperties: {
+          times: coordTimes.length === 1 ? coordTimes[0] : coordTimes
         }
-      }
-      if (applyFeatureLayerFilters) {
-        data = features2.filter(data, graph);
-      } else {
-        context.features().resetStats();
-      }
-      if (mode && mode.id === "select") {
-        surface.call(drawVertices.drawSelected, graph, map2.extent());
-      }
-      surface.call(drawVertices, graph, data, filter2, map2.extent(), fullRedraw).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent()).call(drawLabels, graph, data, filter2, _dimensions, fullRedraw).call(drawPoints, graph, data, filter2);
-      dispatch10.call("drawn", this, { full: true });
-    }
-    map2.init = function() {
-      drawLayers = svgLayers(projection2, context);
-      drawPoints = svgPoints(projection2, context);
-      drawVertices = svgVertices(projection2, context);
-      drawLines = svgLines(projection2, context);
-      drawAreas = svgAreas(projection2, context);
-      drawMidpoints = svgMidpoints(projection2, context);
-      drawLabels = svgLabels(projection2, context);
+      } : {})
     };
-    function editOff() {
-      context.features().resetStats();
-      surface.selectAll(".layer-osm *").remove();
-      surface.selectAll(".layer-touch:not(.markers) *").remove();
-      var allowed = {
-        "browse": true,
-        "save": true,
-        "select-note": true,
-        "select-data": true,
-        "select-error": true
-      };
-      var mode = context.mode();
-      if (mode && !allowed[mode.id]) {
-        context.enter(modeBrowse(context));
-      }
-      dispatch10.call("drawn", this, { full: true });
+    if (((_a3 = feature3.properties) == null ? void 0 : _a3.visibility) !== void 0) {
+      feature3.properties.visibility = feature3.properties.visibility !== "0";
     }
-    function gestureChange(d3_event) {
-      var e = d3_event;
-      e.preventDefault();
-      var props = {
-        deltaMode: 0,
-        deltaY: 1,
-        clientX: e.clientX,
-        clientY: e.clientY,
-        screenX: e.screenX,
-        screenY: e.screenY,
-        x: e.x,
-        y: e.y
+    const id2 = node.getAttribute("id");
+    if (id2 !== null && id2 !== "")
+      feature3.id = id2;
+    return feature3;
+  }
+  function getGroundOverlayBox(node) {
+    const latLonQuad = get1(node, "gx:LatLonQuad");
+    if (latLonQuad) {
+      const ring = fixRing(coord(getCoordinates(node)));
+      return {
+        geometry: {
+          type: "Polygon",
+          coordinates: [ring]
+        }
       };
-      var e22 = new WheelEvent("wheel", props);
-      e22._scale = e.scale;
-      e22._rotation = e.rotation;
-      _selection.node().dispatchEvent(e22);
     }
-    function zoomPan(event, key, transform2) {
-      var source = event && event.sourceEvent || event;
-      var eventTransform = transform2 || event && event.transform;
-      var x = eventTransform.x;
-      var y = eventTransform.y;
-      var k = eventTransform.k;
-      if (source && source.type === "wheel") {
-        if (_pointerDown)
-          return;
-        var detected = utilDetect();
-        var dX = source.deltaX;
-        var dY = source.deltaY;
-        var x2 = x;
-        var y2 = y;
-        var k2 = k;
-        var t0, p02, p1;
-        if (source.deltaMode === 1) {
-          var lines = Math.abs(source.deltaY);
-          var sign2 = source.deltaY > 0 ? 1 : -1;
-          dY = sign2 * clamp(
-            Math.exp((lines - 1) * 0.75) * 4.000244140625,
-            4.000244140625,
-            350.000244140625
-          );
-          if (detected.os !== "mac") {
-            dY *= 5;
-          }
-          t0 = _isTransformed ? _transformLast : _transformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k2 = t0.k * Math.pow(2, -dY / 500);
-          k2 = clamp(k2, kMin, kMax);
-          x2 = p02[0] - p1[0] * k2;
-          y2 = p02[1] - p1[1] * k2;
-        } else if (source._scale) {
-          t0 = _gestureTransformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k2 = t0.k * source._scale;
-          k2 = clamp(k2, kMin, kMax);
-          x2 = p02[0] - p1[0] * k2;
-          y2 = p02[1] - p1[1] * k2;
-        } else if (source.ctrlKey && !isInteger(dY)) {
-          dY *= 6;
-          t0 = _isTransformed ? _transformLast : _transformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k2 = t0.k * Math.pow(2, -dY / 500);
-          k2 = clamp(k2, kMin, kMax);
-          x2 = p02[0] - p1[0] * k2;
-          y2 = p02[1] - p1[1] * k2;
-        } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
-          t0 = _isTransformed ? _transformLast : _transformStart;
-          p02 = _getMouseCoords(source);
-          p1 = t0.invert(p02);
-          k2 = t0.k * Math.pow(2, -dY / 500);
-          k2 = clamp(k2, kMin, kMax);
-          x2 = p02[0] - p1[0] * k2;
-          y2 = p02[1] - p1[1] * k2;
-        } else if (detected.os === "mac" && detected.browser !== "Firefox" && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
-          p1 = projection2.translate();
-          x2 = p1[0] - dX;
-          y2 = p1[1] - dY;
-          k2 = projection2.scale();
-          k2 = clamp(k2, kMin, kMax);
-        }
-        if (x2 !== x || y2 !== y || k2 !== k) {
-          x = x2;
-          y = y2;
-          k = k2;
-          eventTransform = identity2.translate(x2, y2).scale(k2);
-          if (_zoomerPanner._transform) {
-            _zoomerPanner._transform(eventTransform);
-          } else {
-            _selection.node().__zoom = eventTransform;
-          }
+    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 {
+          bbox: bbox2,
+          geometry: {
+            type: "Polygon",
+            coordinates
+          }
+        };
       }
-      if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
-        return;
-      }
-      if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
-        surface.interrupt();
-        dispatch10.call("hitMinZoom", this, map2);
-        setCenterZoom(map2.center(), context.minEditableZoom(), 0, true);
-        scheduleRedraw();
-        dispatch10.call("move", this, map2);
-        return;
-      }
-      projection2.transform(eventTransform);
-      var withinEditableZoom = map2.withinEditableZoom();
-      if (_lastWithinEditableZoom !== withinEditableZoom) {
-        if (_lastWithinEditableZoom !== void 0) {
-          dispatch10.call("crossEditableZoom", this, withinEditableZoom);
+    }
+    return null;
+  }
+  function getGroundOverlay(node, styleMap, schema, options2) {
+    var _a3;
+    const box = getGroundOverlayBox(node);
+    const geometry = (box == null ? void 0 : box.geometry) || null;
+    if (!geometry && options2.skipNullGeometry) {
+      return null;
+    }
+    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 (box == null ? void 0 : box.bbox) {
+      feature3.bbox = box.bbox;
+    }
+    if (((_a3 = feature3.properties) == null ? void 0 : _a3.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;
+    if (!id2 && isElement(parentNode) && parentNode.localName === "CascadingStyle") {
+      id2 = parentNode.getAttribute("kml:id") || parentNode.getAttribute("id");
+    }
+    return normalizeId(id2 || "");
+  }
+  function buildStyleMap(node) {
+    const styleMap = {};
+    for (const style of $(node, "Style")) {
+      styleMap[getStyleId(style)] = extractStyle(style);
+    }
+    for (const map2 of $(node, "StyleMap")) {
+      const id2 = normalizeId(map2.getAttribute("id") || "");
+      val1(map2, "styleUrl", (styleUrl) => {
+        styleUrl = normalizeId(styleUrl);
+        if (styleMap[styleUrl]) {
+          styleMap[id2] = styleMap[styleUrl];
         }
-        _lastWithinEditableZoom = withinEditableZoom;
-      }
-      var scale = k / _transformStart.k;
-      var tX = (x / scale - _transformStart.x) * scale;
-      var tY = (y / scale - _transformStart.y) * scale;
-      if (context.inIntro()) {
-        curtainProjection.transform({
-          x: x - tX,
-          y: y - tY,
-          k
-        });
-      }
-      if (source) {
-        _lastPointerEvent = event;
-      }
-      _isTransformed = true;
-      _transformLast = eventTransform;
-      utilSetTransform(supersurface, tX, tY, scale);
-      scheduleRedraw();
-      dispatch10.call("move", this, map2);
-      function isInteger(val) {
-        return typeof val === "number" && isFinite(val) && Math.floor(val) === val;
-      }
+      });
     }
-    function resetTransform() {
-      if (!_isTransformed)
-        return false;
-      utilSetTransform(supersurface, 0, 0);
-      _isTransformed = false;
-      if (context.inIntro()) {
-        curtainProjection.transform(projection2.transform());
-      }
-      return true;
+    return styleMap;
+  }
+  function buildSchema(node) {
+    const schema = {};
+    for (const field of $(node, "SimpleField")) {
+      schema[field.getAttribute("name") || ""] = typeConverters[field.getAttribute("type") || ""] || typeConverters["string"];
     }
-    function redraw(difference, extent) {
-      if (surface.empty() || !_redrawEnabled)
-        return;
-      if (resetTransform()) {
-        difference = extent = void 0;
-      }
-      var zoom = map2.zoom();
-      var z = String(~~zoom);
-      if (surface.attr("data-zoom") !== z) {
-        surface.attr("data-zoom", z);
-      }
-      var lat = map2.center()[1];
-      var lowzoom = linear3().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
-      surface.classed("low-zoom", zoom <= lowzoom(lat));
-      if (!difference) {
-        supersurface.call(context.background());
-        wrapper.call(drawLayers);
+    return schema;
+  }
+  function* kmlGen(node, options2 = {
+    skipNullGeometry: false
+  }) {
+    const styleMap = buildStyleMap(node);
+    const schema = buildSchema(node);
+    for (const placemark of $(node, "Placemark")) {
+      const feature3 = getPlacemark(placemark, styleMap, schema, options2);
+      if (feature3)
+        yield feature3;
+    }
+    for (const groundOverlay of $(node, "GroundOverlay")) {
+      const feature3 = getGroundOverlay(groundOverlay, styleMap, schema, options2);
+      if (feature3)
+        yield feature3;
+    }
+  }
+  function kml(node, options2 = {
+    skipNullGeometry: false
+  }) {
+    return {
+      type: "FeatureCollection",
+      features: Array.from(kmlGen(node, options2))
+    };
+  }
+
+  // modules/svg/data.js
+  var _initialized = false;
+  var _enabled = false;
+  var _geojson;
+  function svgData(projection2, context, dispatch14) {
+    var throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    var _showLabels = true;
+    var detected = utilDetect();
+    var layer = select_default2(null);
+    var _vtService;
+    var _fileList;
+    var _template;
+    var _src;
+    const supportedFormats = [
+      ".gpx",
+      ".kml",
+      ".geojson",
+      ".json"
+    ];
+    function init2() {
+      if (_initialized) return;
+      _geojson = {};
+      _enabled = true;
+      function over(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        d3_event.dataTransfer.dropEffect = "copy";
       }
-      if (map2.editableDataEnabled() || map2.isInWideSelection()) {
-        context.loadTiles(projection2);
-        drawEditable(difference, extent);
-      } else {
-        editOff();
+      context.container().attr("dropzone", "copy").on("drop.svgData", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        if (!detected.filedrop) return;
+        var f2 = d3_event.dataTransfer.files[0];
+        var extension = getExtension(f2.name);
+        if (!supportedFormats.includes(extension)) return;
+        drawData.fileList(d3_event.dataTransfer.files);
+      }).on("dragenter.svgData", over).on("dragexit.svgData", over).on("dragover.svgData", over);
+      _initialized = true;
+    }
+    function getService() {
+      if (services.vectorTile && !_vtService) {
+        _vtService = services.vectorTile;
+        _vtService.event.on("loadedData", throttledRedraw);
+      } else if (!services.vectorTile && _vtService) {
+        _vtService = null;
       }
-      _transformStart = projection2.transform();
-      return map2;
+      return _vtService;
     }
-    var immediateRedraw = function(difference, extent) {
-      if (!difference && !extent)
-        cancelPendingRedraw();
-      redraw(difference, extent);
-    };
-    map2.lastPointerEvent = function() {
-      return _lastPointerEvent;
-    };
-    map2.mouse = function(d3_event) {
-      var event = d3_event || _lastPointerEvent;
-      if (event) {
-        var s;
-        while (s = event.sourceEvent) {
-          event = s;
+    function showLayer() {
+      layerOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
+      });
+    }
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", layerOff);
+    }
+    function layerOn() {
+      layer.style("display", "block");
+    }
+    function layerOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function ensureIDs(gj) {
+      if (!gj) return null;
+      if (gj.type === "FeatureCollection") {
+        for (var i3 = 0; i3 < gj.features.length; i3++) {
+          ensureFeatureID(gj.features[i3]);
         }
-        return _getMouseCoords(event);
-      }
-      return null;
-    };
-    map2.mouseCoordinates = function() {
-      var coord2 = map2.mouse() || pxCenter();
-      return projection2.invert(coord2);
-    };
-    map2.dblclickZoomEnable = function(val) {
-      if (!arguments.length)
-        return _dblClickZoomEnabled;
-      _dblClickZoomEnabled = val;
-      return map2;
-    };
-    map2.redrawEnable = function(val) {
-      if (!arguments.length)
-        return _redrawEnabled;
-      _redrawEnabled = val;
-      return map2;
-    };
-    map2.isTransformed = function() {
-      return _isTransformed;
-    };
-    function setTransform(t2, duration, force) {
-      var t = projection2.transform();
-      if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y)
-        return false;
-      if (duration) {
-        _selection.transition().duration(duration).on("start", function() {
-          map2.startEase();
-        }).call(_zoomerPanner.transform, identity2.translate(t2.x, t2.y).scale(t2.k));
       } else {
-        projection2.transform(t2);
-        _transformStart = t2;
-        _selection.call(_zoomerPanner.transform, _transformStart);
+        ensureFeatureID(gj);
       }
-      return true;
+      return gj;
     }
-    function setCenterZoom(loc2, z2, duration, force) {
-      var c = map2.center();
-      var z = map2.zoom();
-      if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force)
-        return false;
-      var proj = geoRawMercator().transform(projection2.transform());
-      var k2 = clamp(geoZoomToScale(z2, TILESIZE), kMin, kMax);
-      proj.scale(k2);
-      var t = proj.translate();
-      var point = proj(loc2);
-      var center = pxCenter();
-      t[0] += center[0] - point[0];
-      t[1] += center[1] - point[1];
-      return setTransform(identity2.translate(t[0], t[1]).scale(k2), duration, force);
+    function ensureFeatureID(feature3) {
+      if (!feature3) return;
+      feature3.__featurehash__ = utilHashcode((0, import_fast_json_stable_stringify.default)(feature3));
+      return feature3;
     }
-    map2.pan = function(delta, duration) {
-      var t = projection2.translate();
-      var k = projection2.scale();
-      t[0] += delta[0];
-      t[1] += delta[1];
-      if (duration) {
-        _selection.transition().duration(duration).on("start", function() {
-          map2.startEase();
-        }).call(_zoomerPanner.transform, identity2.translate(t[0], t[1]).scale(k));
+    function getFeatures(gj) {
+      if (!gj) return [];
+      if (gj.type === "FeatureCollection") {
+        return gj.features;
       } else {
-        projection2.translate(t);
-        _transformStart = projection2.transform();
-        _selection.call(_zoomerPanner.transform, _transformStart);
-        dispatch10.call("move", this, map2);
-        immediateRedraw();
+        return [gj];
       }
-      return map2;
-    };
-    map2.dimensions = function(val) {
-      if (!arguments.length)
-        return _dimensions;
-      _dimensions = val;
-      drawLayers.dimensions(_dimensions);
-      context.background().dimensions(_dimensions);
-      projection2.clipExtent([[0, 0], _dimensions]);
-      _getMouseCoords = utilFastMouse(supersurface.node());
-      scheduleRedraw();
-      return map2;
-    };
-    function zoomIn(delta) {
-      setCenterZoom(map2.center(), ~~map2.zoom() + delta, 250, true);
     }
-    function zoomOut(delta) {
-      setCenterZoom(map2.center(), ~~map2.zoom() - delta, 250, true);
+    function featureKey(d2) {
+      return d2.__featurehash__;
     }
-    map2.zoomIn = function() {
-      zoomIn(1);
-    };
-    map2.zoomInFurther = function() {
-      zoomIn(4);
-    };
-    map2.canZoomIn = function() {
-      return map2.zoom() < maxZoom;
-    };
-    map2.zoomOut = function() {
-      zoomOut(1);
-    };
-    map2.zoomOutFurther = function() {
-      zoomOut(4);
-    };
-    map2.canZoomOut = function() {
-      return map2.zoom() > minZoom2;
-    };
-    map2.center = function(loc2) {
-      if (!arguments.length) {
-        return projection2.invert(pxCenter());
-      }
-      if (setCenterZoom(loc2, map2.zoom())) {
-        dispatch10.call("move", this, map2);
-      }
-      scheduleRedraw();
-      return map2;
-    };
-    map2.unobscuredCenterZoomEase = function(loc, zoom) {
-      var offset = map2.unobscuredOffsetPx();
-      var proj = geoRawMercator().transform(projection2.transform());
-      proj.scale(geoZoomToScale(zoom, TILESIZE));
-      var locPx = proj(loc);
-      var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
-      var offsetLoc = proj.invert(offsetLocPx);
-      map2.centerZoomEase(offsetLoc, zoom);
-    };
-    map2.unobscuredOffsetPx = function() {
-      var openPane = context.container().select(".map-panes .map-pane.shown");
-      if (!openPane.empty()) {
-        return [openPane.node().offsetWidth / 2, 0];
+    function isPolygon(d2) {
+      return d2.geometry.type === "Polygon" || d2.geometry.type === "MultiPolygon";
+    }
+    function clipPathID(d2) {
+      return "ideditor-data-" + d2.__featurehash__ + "-clippath";
+    }
+    function featureClasses(d2) {
+      return [
+        "data" + d2.__featurehash__,
+        d2.geometry.type,
+        isPolygon(d2) ? "area" : "",
+        d2.__layerID__ || ""
+      ].filter(Boolean).join(" ");
+    }
+    function drawData(selection2) {
+      var vtService = getService();
+      var getPath = svgPath(projection2).geojson;
+      var getAreaPath = svgPath(projection2, null, true).geojson;
+      var hasData = drawData.hasData();
+      layer = selection2.selectAll(".layer-mapdata").data(_enabled && hasData ? [0] : []);
+      layer.exit().remove();
+      layer = layer.enter().append("g").attr("class", "layer-mapdata").merge(layer);
+      var surface = context.surface();
+      if (!surface || surface.empty()) return;
+      var geoData, polygonData;
+      if (_template && vtService) {
+        var sourceID = _template;
+        vtService.loadTiles(sourceID, _template, projection2);
+        geoData = vtService.data(sourceID, projection2);
+      } else {
+        geoData = getFeatures(_geojson);
       }
-      return [0, 0];
-    };
-    map2.zoom = function(z2) {
-      if (!arguments.length) {
-        return Math.max(geoScaleToZoom(projection2.scale(), TILESIZE), 0);
+      geoData = geoData.filter(getPath);
+      polygonData = geoData.filter(isPolygon);
+      var clipPaths = surface.selectAll("defs").selectAll(".clipPath-data").data(polygonData, featureKey);
+      clipPaths.exit().remove();
+      var clipPathsEnter = clipPaths.enter().append("clipPath").attr("class", "clipPath-data").attr("id", clipPathID);
+      clipPathsEnter.append("path");
+      clipPaths.merge(clipPathsEnter).selectAll("path").attr("d", getAreaPath);
+      var datagroups = layer.selectAll("g.datagroup").data(["fill", "shadow", "stroke"]);
+      datagroups = datagroups.enter().append("g").attr("class", function(d2) {
+        return "datagroup datagroup-" + d2;
+      }).merge(datagroups);
+      var pathData = {
+        fill: polygonData,
+        shadow: geoData,
+        stroke: geoData
+      };
+      var paths = datagroups.selectAll("path").data(function(layer2) {
+        return pathData[layer2];
+      }, featureKey);
+      paths.exit().remove();
+      paths = paths.enter().append("path").attr("class", function(d2) {
+        var datagroup = this.parentNode.__data__;
+        return "pathdata " + datagroup + " " + featureClasses(d2);
+      }).attr("clip-path", function(d2) {
+        var datagroup = this.parentNode.__data__;
+        return datagroup === "fill" ? "url(#" + clipPathID(d2) + ")" : null;
+      }).merge(paths).attr("d", function(d2) {
+        var datagroup = this.parentNode.__data__;
+        return datagroup === "fill" ? getAreaPath(d2) : getPath(d2);
+      });
+      layer.call(drawLabels, "label-halo", geoData).call(drawLabels, "label", geoData);
+      function drawLabels(selection3, textClass, data) {
+        var labelPath = path_default(projection2);
+        var labelData = data.filter(function(d2) {
+          return _showLabels && d2.properties && (d2.properties.desc || d2.properties.name);
+        });
+        var labels = selection3.selectAll("text." + textClass).data(labelData, featureKey);
+        labels.exit().remove();
+        labels = labels.enter().append("text").attr("class", function(d2) {
+          return textClass + " " + featureClasses(d2);
+        }).merge(labels).text(function(d2) {
+          return d2.properties.desc || d2.properties.name;
+        }).attr("x", function(d2) {
+          var centroid = labelPath.centroid(d2);
+          return centroid[0] + 11;
+        }).attr("y", function(d2) {
+          var centroid = labelPath.centroid(d2);
+          return centroid[1];
+        });
       }
-      if (z2 < _minzoom) {
-        surface.interrupt();
-        dispatch10.call("hitMinZoom", this, map2);
-        z2 = context.minEditableZoom();
+    }
+    function getExtension(fileName) {
+      if (!fileName) return;
+      var re3 = /\.(gpx|kml|(geo)?json|png)$/i;
+      var match = fileName.toLowerCase().match(re3);
+      return match && match.length && match[0];
+    }
+    function xmlToDom(textdata) {
+      return new DOMParser().parseFromString(textdata, "text/xml");
+    }
+    function stringifyGeojsonProperties(feature3) {
+      const properties = feature3.properties;
+      for (const key in properties) {
+        const property = properties[key];
+        if (typeof property === "number" || typeof property === "boolean" || Array.isArray(property)) {
+          properties[key] = property.toString();
+        } else if (property === null) {
+          properties[key] = "null";
+        } else if (typeof property === "object") {
+          properties[key] = JSON.stringify(property);
+        }
       }
-      if (setCenterZoom(map2.center(), z2)) {
-        dispatch10.call("move", this, map2);
+    }
+    drawData.setFile = function(extension, data) {
+      _template = null;
+      _fileList = null;
+      _geojson = null;
+      _src = null;
+      var gj;
+      switch (extension) {
+        case ".gpx":
+          gj = gpx(xmlToDom(data));
+          break;
+        case ".kml":
+          gj = kml(xmlToDom(data));
+          break;
+        case ".geojson":
+        case ".json":
+          gj = JSON.parse(data);
+          if (gj.type === "FeatureCollection") {
+            gj.features.forEach(stringifyGeojsonProperties);
+          } else if (gj.type === "Feature") {
+            stringifyGeojsonProperties(gj);
+          }
+          break;
       }
-      scheduleRedraw();
-      return map2;
-    };
-    map2.centerZoom = function(loc2, z2) {
-      if (setCenterZoom(loc2, z2)) {
-        dispatch10.call("move", this, map2);
+      gj = gj || {};
+      if (Object.keys(gj).length) {
+        _geojson = ensureIDs(gj);
+        _src = extension + " data file";
+        this.fitZoom();
       }
-      scheduleRedraw();
-      return map2;
-    };
-    map2.zoomTo = function(entity) {
-      var extent = entity.extent(context.graph());
-      if (!isFinite(extent.area()))
-        return map2;
-      var z2 = clamp(map2.trimmedExtentZoom(extent), 0, 20);
-      return map2.centerZoom(extent.center(), z2);
-    };
-    map2.centerEase = function(loc2, duration) {
-      duration = duration || 250;
-      setCenterZoom(loc2, map2.zoom(), duration);
-      return map2;
-    };
-    map2.zoomEase = function(z2, duration) {
-      duration = duration || 250;
-      setCenterZoom(map2.center(), z2, duration, false);
-      return map2;
-    };
-    map2.centerZoomEase = function(loc2, z2, duration) {
-      duration = duration || 250;
-      setCenterZoom(loc2, z2, duration, false);
-      return map2;
+      dispatch14.call("change");
+      return this;
     };
-    map2.transformEase = function(t2, duration) {
-      duration = duration || 250;
-      setTransform(t2, duration, false);
-      return map2;
+    drawData.showLabels = function(val) {
+      if (!arguments.length) return _showLabels;
+      _showLabels = val;
+      return this;
     };
-    map2.zoomToEase = function(obj, duration) {
-      var extent;
-      if (Array.isArray(obj)) {
-        obj.forEach(function(entity) {
-          var entityExtent = entity.extent(context.graph());
-          if (!extent) {
-            extent = entityExtent;
-          } else {
-            extent = extent.extend(entityExtent);
-          }
-        });
+    drawData.enabled = function(val) {
+      if (!arguments.length) return _enabled;
+      _enabled = val;
+      if (_enabled) {
+        showLayer();
       } else {
-        extent = obj.extent(context.graph());
+        hideLayer();
       }
-      if (!isFinite(extent.area()))
-        return map2;
-      var z2 = clamp(map2.trimmedExtentZoom(extent), 0, 20);
-      return map2.centerZoomEase(extent.center(), z2, duration);
-    };
-    map2.startEase = function() {
-      utilBindOnce(surface, _pointerPrefix + "down.ease", function() {
-        map2.cancelEase();
-      });
-      return map2;
+      dispatch14.call("change");
+      return this;
     };
-    map2.cancelEase = function() {
-      _selection.interrupt();
-      return map2;
+    drawData.hasData = function() {
+      var gj = _geojson || {};
+      return !!(_template || Object.keys(gj).length);
     };
-    map2.extent = function(val) {
-      if (!arguments.length) {
-        return new geoExtent(
-          projection2.invert([0, _dimensions[1]]),
-          projection2.invert([_dimensions[0], 0])
-        );
-      } else {
-        var extent = geoExtent(val);
-        map2.centerZoom(extent.center(), map2.extentZoom(extent));
+    drawData.template = function(val, src) {
+      if (!arguments.length) return _template;
+      var osm = context.connection();
+      if (osm) {
+        var blocklists = osm.imageryBlocklists();
+        var fail = false;
+        var tested = 0;
+        var regex;
+        for (var i3 = 0; i3 < blocklists.length; i3++) {
+          regex = blocklists[i3];
+          fail = regex.test(val);
+          tested++;
+          if (fail) break;
+        }
+        if (!tested) {
+          regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
+          fail = regex.test(val);
+        }
       }
+      _template = val;
+      _fileList = null;
+      _geojson = null;
+      _src = src || "vectortile:" + val.split(/[?#]/)[0];
+      dispatch14.call("change");
+      return this;
     };
-    map2.trimmedExtent = function(val) {
-      if (!arguments.length) {
-        var headerY = 71;
-        var footerY = 30;
-        var pad2 = 10;
-        return new geoExtent(
-          projection2.invert([pad2, _dimensions[1] - footerY - pad2]),
-          projection2.invert([_dimensions[0] - pad2, headerY + pad2])
-        );
-      } else {
-        var extent = geoExtent(val);
-        map2.centerZoom(extent.center(), map2.trimmedExtentZoom(extent));
+    drawData.geojson = function(gj, src) {
+      if (!arguments.length) return _geojson;
+      _template = null;
+      _fileList = null;
+      _geojson = null;
+      _src = null;
+      gj = gj || {};
+      if (Object.keys(gj).length) {
+        _geojson = ensureIDs(gj);
+        _src = src || "unknown.geojson";
       }
+      dispatch14.call("change");
+      return this;
     };
-    function calcExtentZoom(extent, dim) {
-      var tl = projection2([extent[0][0], extent[1][1]]);
-      var br = projection2([extent[1][0], extent[0][1]]);
-      var hFactor = (br[0] - tl[0]) / dim[0];
-      var vFactor = (br[1] - tl[1]) / dim[1];
-      var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
-      var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
-      var newZoom = map2.zoom() - Math.max(hZoomDiff, vZoomDiff);
-      return newZoom;
-    }
-    map2.extentZoom = function(val) {
-      return calcExtentZoom(geoExtent(val), _dimensions);
-    };
-    map2.trimmedExtentZoom = function(val) {
-      var trimY = 120;
-      var trimX = 40;
-      var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
-      return calcExtentZoom(geoExtent(val), trimmed);
-    };
-    map2.withinEditableZoom = function() {
-      return map2.zoom() >= context.minEditableZoom();
-    };
-    map2.isInWideSelection = function() {
-      return !map2.withinEditableZoom() && context.selectedIDs().length;
-    };
-    map2.editableDataEnabled = function(skipZoomCheck) {
-      var layer = context.layers().layer("osm");
-      if (!layer || !layer.enabled())
-        return false;
-      return skipZoomCheck || map2.withinEditableZoom();
-    };
-    map2.notesEditable = function() {
-      var layer = context.layers().layer("notes");
-      if (!layer || !layer.enabled())
-        return false;
-      return map2.withinEditableZoom();
-    };
-    map2.minzoom = function(val) {
-      if (!arguments.length)
-        return _minzoom;
-      _minzoom = val;
-      return map2;
-    };
-    map2.toggleHighlightEdited = function() {
-      surface.classed("highlight-edited", !surface.classed("highlight-edited"));
-      map2.pan([0, 0]);
-      dispatch10.call("changeHighlighting", this);
-    };
-    map2.areaFillOptions = ["wireframe", "partial", "full"];
-    map2.activeAreaFill = function(val) {
-      if (!arguments.length)
-        return corePreferences("area-fill") || "partial";
-      corePreferences("area-fill", val);
-      if (val !== "wireframe") {
-        corePreferences("area-fill-toggle", val);
-      }
-      updateAreaFill();
-      map2.pan([0, 0]);
-      dispatch10.call("changeAreaFill", this);
-      return map2;
+    drawData.fileList = function(fileList) {
+      if (!arguments.length) return _fileList;
+      _template = null;
+      _geojson = null;
+      _src = null;
+      _fileList = fileList;
+      if (!fileList || !fileList.length) return this;
+      var f2 = fileList[0];
+      var extension = getExtension(f2.name);
+      var reader = new FileReader();
+      reader.onload = /* @__PURE__ */ function() {
+        return function(e3) {
+          drawData.setFile(extension, e3.target.result);
+        };
+      }(f2);
+      reader.readAsText(f2);
+      return this;
     };
-    map2.toggleWireframe = function() {
-      var activeFill = map2.activeAreaFill();
-      if (activeFill === "wireframe") {
-        activeFill = corePreferences("area-fill-toggle") || "partial";
+    drawData.url = function(url, defaultExtension) {
+      _template = null;
+      _fileList = null;
+      _geojson = null;
+      _src = null;
+      var testUrl = url.split(/[?#]/)[0];
+      var extension = getExtension(testUrl) || defaultExtension;
+      if (extension) {
+        _template = null;
+        text_default3(url).then(function(data) {
+          drawData.setFile(extension, data);
+        }).catch(function() {
+        });
       } else {
-        activeFill = "wireframe";
+        drawData.template(url);
       }
-      map2.activeAreaFill(activeFill);
+      return this;
     };
-    function updateAreaFill() {
-      var activeFill = map2.activeAreaFill();
-      map2.areaFillOptions.forEach(function(opt) {
-        surface.classed("fill-" + opt, Boolean(opt === activeFill));
-      });
-    }
-    map2.layers = () => drawLayers;
-    map2.doubleUpHandler = function() {
-      return _doubleUpHandler;
+    drawData.getSrc = function() {
+      return _src || "";
+    };
+    drawData.fitZoom = function() {
+      var features = getFeatures(_geojson);
+      if (!features.length) return;
+      var map2 = context.map();
+      var viewport = map2.trimmedExtent().polygon();
+      var coords = features.reduce(function(coords2, feature3) {
+        var geom = feature3.geometry;
+        if (!geom) return coords2;
+        var c2 = geom.coordinates;
+        switch (geom.type) {
+          case "Point":
+            c2 = [c2];
+          case "MultiPoint":
+          case "LineString":
+            break;
+          case "MultiPolygon":
+            c2 = utilArrayFlatten(c2);
+          case "Polygon":
+          case "MultiLineString":
+            c2 = utilArrayFlatten(c2);
+            break;
+        }
+        return utilArrayUnion(coords2, c2);
+      }, []);
+      if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
+        var extent = geoExtent(bounds_default({ type: "LineString", coordinates: coords }));
+        map2.centerZoom(extent.center(), map2.trimmedExtentZoom(extent));
+      }
+      return this;
     };
-    return utilRebind(map2, dispatch10, "on");
+    init2();
+    return drawData;
   }
 
-  // modules/renderer/photos.js
-  function rendererPhotos(context) {
-    var dispatch10 = dispatch_default("change");
-    var _layerIDs = ["streetside", "mapillary", "mapillary-map-features", "mapillary-signs", "kartaview"];
-    var _allPhotoTypes = ["flat", "panoramic"];
-    var _shownPhotoTypes = _allPhotoTypes.slice();
-    var _dateFilters = ["fromDate", "toDate"];
-    var _fromDate;
-    var _toDate;
-    var _usernames;
-    function photos() {
-    }
-    function updateStorage() {
-      if (window.mocha)
-        return;
-      var hash = utilStringQs(window.location.hash);
-      var enabled = context.layers().all().filter(function(d) {
-        return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
-      }).map(function(d) {
-        return d.id;
-      });
-      if (enabled.length) {
-        hash.photo_overlay = enabled.join(",");
-      } else {
-        delete hash.photo_overlay;
+  // modules/svg/debug.js
+  function svgDebug(projection2, context) {
+    function drawDebug(selection2) {
+      const showTile = context.getDebug("tile");
+      const showCollision = context.getDebug("collision");
+      const showImagery = context.getDebug("imagery");
+      const showTouchTargets = context.getDebug("target");
+      const showDownloaded = context.getDebug("downloaded");
+      let debugData = [];
+      if (showTile) {
+        debugData.push({ class: "red", label: "tile" });
       }
-      window.location.replace("#" + utilQsString(hash, true));
-    }
-    photos.overlayLayerIDs = function() {
-      return _layerIDs;
-    };
-    photos.allPhotoTypes = function() {
-      return _allPhotoTypes;
-    };
-    photos.dateFilters = function() {
-      return _dateFilters;
-    };
-    photos.dateFilterValue = function(val) {
-      return val === _dateFilters[0] ? _fromDate : _toDate;
-    };
-    photos.setDateFilter = function(type3, val, updateUrl) {
-      var date = val && new Date(val);
-      if (date && !isNaN(date)) {
-        val = date.toISOString().slice(0, 10);
-      } else {
-        val = null;
+      if (showCollision) {
+        debugData.push({ class: "yellow", label: "collision" });
       }
-      if (type3 === _dateFilters[0]) {
-        _fromDate = val;
-        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
-          _toDate = _fromDate;
-        }
+      if (showImagery) {
+        debugData.push({ class: "orange", label: "imagery" });
       }
-      if (type3 === _dateFilters[1]) {
-        _toDate = val;
-        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
-          _fromDate = _toDate;
-        }
+      if (showTouchTargets) {
+        debugData.push({ class: "pink", label: "touchTargets" });
       }
-      dispatch10.call("change", this);
-      if (updateUrl) {
-        var rangeString;
-        if (_fromDate || _toDate) {
-          rangeString = (_fromDate || "") + "_" + (_toDate || "");
-        }
-        setUrlFilterValue("photo_dates", rangeString);
+      if (showDownloaded) {
+        debugData.push({ class: "purple", label: "downloaded" });
       }
-    };
-    photos.setUsernameFilter = function(val, updateUrl) {
-      if (val && typeof val === "string")
-        val = val.replace(/;/g, ",").split(",");
-      if (val) {
-        val = val.map((d) => d.trim()).filter(Boolean);
-        if (!val.length) {
-          val = null;
-        }
+      let legend = context.container().select(".main-content").selectAll(".debug-legend").data(debugData.length ? [0] : []);
+      legend.exit().remove();
+      legend = legend.enter().append("div").attr("class", "fillD debug-legend").merge(legend);
+      let legendItems = legend.selectAll(".debug-legend-item").data(debugData, (d2) => d2.label);
+      legendItems.exit().remove();
+      legendItems.enter().append("span").attr("class", (d2) => "debug-legend-item ".concat(d2.class)).text((d2) => d2.label);
+      let layer = selection2.selectAll(".layer-debug").data(showImagery || showDownloaded ? [0] : []);
+      layer.exit().remove();
+      layer = layer.enter().append("g").attr("class", "layer-debug").merge(layer);
+      const extent = context.map().extent();
+      _mainFileFetcher.get("imagery").then((d2) => {
+        const hits = showImagery && d2.query.bbox(extent.rectangle(), true) || [];
+        const features = hits.map((d4) => d4.features[d4.id]);
+        let imagery = layer.selectAll("path.debug-imagery").data(features);
+        imagery.exit().remove();
+        imagery.enter().append("path").attr("class", "debug-imagery debug orange");
+      }).catch(() => {
+      });
+      const osm = context.connection();
+      let dataDownloaded = [];
+      if (osm && showDownloaded) {
+        const rtree = osm.caches("get").tile.rtree;
+        dataDownloaded = rtree.all().map((bbox2) => {
+          return {
+            type: "Feature",
+            properties: { id: bbox2.id },
+            geometry: {
+              type: "Polygon",
+              coordinates: [[
+                [bbox2.minX, bbox2.minY],
+                [bbox2.minX, bbox2.maxY],
+                [bbox2.maxX, bbox2.maxY],
+                [bbox2.maxX, bbox2.minY],
+                [bbox2.minX, bbox2.minY]
+              ]]
+            }
+          };
+        });
       }
-      _usernames = val;
-      dispatch10.call("change", this);
-      if (updateUrl) {
-        var hashString;
-        if (_usernames) {
-          hashString = _usernames.join(",");
-        }
-        setUrlFilterValue("photo_username", hashString);
-      }
-    };
-    function setUrlFilterValue(property, val) {
-      if (!window.mocha) {
-        var hash = utilStringQs(window.location.hash);
-        if (val) {
-          if (hash[property] === val)
-            return;
-          hash[property] = val;
-        } else {
-          if (!(property in hash))
-            return;
-          delete hash[property];
-        }
-        window.location.replace("#" + utilQsString(hash, true));
-      }
-    }
-    function showsLayer(id2) {
-      var layer = context.layers().layer(id2);
-      return layer && layer.supported() && layer.enabled();
+      let downloaded = layer.selectAll("path.debug-downloaded").data(showDownloaded ? dataDownloaded : []);
+      downloaded.exit().remove();
+      downloaded.enter().append("path").attr("class", "debug-downloaded debug purple");
+      layer.selectAll("path").attr("d", svgPath(projection2).geojson);
     }
-    photos.shouldFilterByDate = function() {
-      return showsLayer("mapillary") || showsLayer("kartaview") || showsLayer("streetside");
-    };
-    photos.shouldFilterByPhotoType = function() {
-      return showsLayer("mapillary") || showsLayer("streetside") && showsLayer("kartaview");
-    };
-    photos.shouldFilterByUsername = function() {
-      return !showsLayer("mapillary") && showsLayer("kartaview") && !showsLayer("streetside");
-    };
-    photos.showsPhotoType = function(val) {
-      if (!photos.shouldFilterByPhotoType())
-        return true;
-      return _shownPhotoTypes.indexOf(val) !== -1;
-    };
-    photos.showsFlat = function() {
-      return photos.showsPhotoType("flat");
-    };
-    photos.showsPanoramic = function() {
-      return photos.showsPhotoType("panoramic");
-    };
-    photos.fromDate = function() {
-      return _fromDate;
-    };
-    photos.toDate = function() {
-      return _toDate;
-    };
-    photos.togglePhotoType = function(val) {
-      var index = _shownPhotoTypes.indexOf(val);
-      if (index !== -1) {
-        _shownPhotoTypes.splice(index, 1);
+    drawDebug.enabled = function() {
+      if (!arguments.length) {
+        return context.getDebug("tile") || context.getDebug("collision") || context.getDebug("imagery") || context.getDebug("target") || context.getDebug("downloaded");
       } else {
-        _shownPhotoTypes.push(val);
+        return this;
       }
-      dispatch10.call("change", this);
-      return photos;
-    };
-    photos.usernames = function() {
-      return _usernames;
     };
-    photos.init = function() {
-      var hash = utilStringQs(window.location.hash);
-      if (hash.photo_dates) {
-        var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
-        this.setDateFilter("fromDate", parts && parts.length >= 2 && parts[1], false);
-        this.setDateFilter("toDate", parts && parts.length >= 3 && parts[2], false);
-      }
-      if (hash.photo_username) {
-        this.setUsernameFilter(hash.photo_username, false);
-      }
-      if (hash.photo_overlay) {
-        var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ",").split(",");
-        hashOverlayIDs.forEach(function(id2) {
-          if (id2 === "openstreetcam")
-            id2 = "kartaview";
-          var layer2 = _layerIDs.indexOf(id2) !== -1 && context.layers().layer(id2);
-          if (layer2 && !layer2.enabled())
-            layer2.enabled(true);
-        });
+    return drawDebug;
+  }
+
+  // modules/svg/defs.js
+  function svgDefs(context) {
+    var _defsSelection = select_default2(null);
+    var _spritesheetIds = [
+      "iD-sprite",
+      "maki-sprite",
+      "temaki-sprite",
+      "fa-sprite",
+      "roentgen-sprite",
+      "community-sprite"
+    ];
+    function drawDefs(selection2) {
+      _defsSelection = selection2.append("defs");
+      _defsSelection.append("marker").attr("id", "ideditor-oneway-marker").attr("viewBox", "0 0 10 5").attr("refX", 2.5).attr("refY", 2.5).attr("markerWidth", 2).attr("markerHeight", 2).attr("markerUnits", "strokeWidth").attr("orient", "auto").append("path").attr("class", "oneway-marker-path").attr("d", "M 5,3 L 0,3 L 0,2 L 5,2 L 5,0 L 10,2.5 L 5,5 z").attr("stroke", "none").attr("fill", "#000").attr("opacity", "0.75");
+      function addSidedMarker(name, color2, offset) {
+        _defsSelection.append("marker").attr("id", "ideditor-sided-marker-" + name).attr("viewBox", "0 0 2 2").attr("refX", 1).attr("refY", -offset).attr("markerWidth", 1.5).attr("markerHeight", 1.5).attr("markerUnits", "strokeWidth").attr("orient", "auto").append("path").attr("class", "sided-marker-path sided-marker-" + name + "-path").attr("d", "M 0,0 L 1,1 L 2,0 z").attr("stroke", "none").attr("fill", color2);
       }
-      if (hash.photo) {
-        var photoIds = hash.photo.replace(/;/g, ",").split(",");
-        var photoId = photoIds.length && photoIds[0].trim();
-        var results = /(.*)\/(.*)/g.exec(photoId);
-        if (results && results.length >= 3) {
-          var serviceId = results[1];
-          if (serviceId === "openstreetcam")
-            serviceId = "kartaview";
-          var photoKey = results[2];
-          var service = services[serviceId];
-          if (service && service.ensureViewerLoaded) {
-            var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
-            if (layer && !layer.enabled())
-              layer.enabled(true);
-            var baselineTime = Date.now();
-            service.on("loadedImages.rendererPhotos", function() {
-              if (Date.now() - baselineTime > 45e3) {
-                service.on("loadedImages.rendererPhotos", null);
-                return;
-              }
-              if (!service.cachedImage(photoKey))
-                return;
-              service.on("loadedImages.rendererPhotos", null);
-              service.ensureViewerLoaded(context).then(function() {
-                service.selectImage(context, photoKey).showViewer(context);
-              });
-            });
+      addSidedMarker("natural", "rgb(170, 170, 170)", 0);
+      addSidedMarker("coastline", "#77dede", 1);
+      addSidedMarker("waterway", "#77dede", 1);
+      addSidedMarker("barrier", "#ddd", 1);
+      addSidedMarker("man_made", "#fff", 0);
+      _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"],
+        ["cemetery_christian", "cemetery_christian"],
+        ["cemetery_buddhist", "cemetery_buddhist"],
+        ["cemetery_muslim", "cemetery_muslim"],
+        ["cemetery_jewish", "cemetery_jewish"],
+        ["farmland", "farmland"],
+        ["farmyard", "farmyard"],
+        ["forest", "forest"],
+        ["forest_broadleaved", "forest_broadleaved"],
+        ["forest_needleleaved", "forest_needleleaved"],
+        ["forest_leafless", "forest_leafless"],
+        ["golf_green", "grass"],
+        ["grass", "grass"],
+        ["landfill", "landfill"],
+        ["meadow", "grass"],
+        ["orchard", "orchard"],
+        ["pond", "pond"],
+        ["quarry", "quarry"],
+        ["scrub", "bushes"],
+        ["vineyard", "vineyard"],
+        ["water_standing", "lines"],
+        ["waves", "waves"],
+        ["wetland", "wetland"],
+        ["wetland_marsh", "wetland_marsh"],
+        ["wetland_swamp", "wetland_swamp"],
+        ["wetland_bog", "wetland_bog"],
+        ["wetland_reedbed", "wetland_reedbed"]
+      ]).enter().append("pattern").attr("id", function(d2) {
+        return "ideditor-pattern-" + d2[0];
+      }).attr("width", 32).attr("height", 32).attr("patternUnits", "userSpaceOnUse");
+      patterns2.append("rect").attr("x", 0).attr("y", 0).attr("width", 32).attr("height", 32).attr("class", function(d2) {
+        return "pattern-color-" + d2[0];
+      });
+      patterns2.append("image").attr("x", 0).attr("y", 0).attr("width", 32).attr("height", 32).attr("xlink:href", function(d2) {
+        return context.imagePath("pattern/" + d2[1] + ".png");
+      });
+      _defsSelection.selectAll("clipPath").data([12, 18, 20, 32, 45]).enter().append("clipPath").attr("id", function(d2) {
+        return "ideditor-clip-square-" + d2;
+      }).append("rect").attr("x", 0).attr("y", 0).attr("width", function(d2) {
+        return d2;
+      }).attr("height", function(d2) {
+        return d2;
+      });
+      addSprites(_spritesheetIds, true);
+    }
+    function addSprites(ids, overrideColors) {
+      _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
+      var spritesheets = _defsSelection.selectAll(".spritesheet").data(_spritesheetIds);
+      spritesheets.enter().append("g").attr("class", function(d2) {
+        return "spritesheet spritesheet-" + d2;
+      }).each(function(d2) {
+        var url = context.imagePath(d2 + ".svg");
+        var node = select_default2(this).node();
+        svg(url).then(function(svg2) {
+          node.appendChild(
+            select_default2(svg2.documentElement).attr("id", "ideditor-" + d2).node()
+          );
+          if (overrideColors && d2 !== "iD-sprite") {
+            select_default2(node).selectAll("path").attr("fill", "currentColor");
           }
-        }
-      }
-      context.layers().on("change.rendererPhotos", updateStorage);
-    };
-    return utilRebind(photos, dispatch10, "on");
+        }).catch(function() {
+        });
+      });
+      spritesheets.exit().remove();
+    }
+    drawDefs.addSprites = addSprites;
+    return drawDefs;
   }
 
-  // modules/ui/account.js
-  function uiAccount(context) {
-    const osm = context.connection();
-    function updateUserDetails(selection2) {
-      if (!osm)
-        return;
-      if (!osm.authenticated()) {
-        render(selection2, null);
-      } else {
-        osm.userDetails((err, user) => render(selection2, user));
+  // modules/svg/keepRight.js
+  var _layerEnabled = false;
+  var _qaService;
+  function svgKeepRight(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(() => dispatch14.call("change"), 1e3);
+    const minZoom5 = 12;
+    let touchLayer = select_default2(null);
+    let drawLayer = select_default2(null);
+    let layerVisible = false;
+    function markerPath(selection2, klass) {
+      selection2.attr("class", klass).attr("transform", "translate(-4, -24)").attr("d", "M11.6,6.2H7.1l1.4-5.1C8.6,0.6,8.1,0,7.5,0H2.2C1.7,0,1.3,0.3,1.3,0.8L0,10.2c-0.1,0.6,0.4,1.1,0.9,1.1h4.6l-1.8,7.6C3.6,19.4,4.1,20,4.7,20c0.3,0,0.6-0.2,0.8-0.5l6.9-11.9C12.7,7,12.3,6.2,11.6,6.2z");
+    }
+    function getService() {
+      if (services.keepRight && !_qaService) {
+        _qaService = services.keepRight;
+        _qaService.on("loaded", throttledRedraw);
+      } else if (!services.keepRight && _qaService) {
+        _qaService = null;
       }
+      return _qaService;
     }
-    function render(selection2, user) {
-      let userInfo = selection2.select(".userInfo");
-      let loginLogout = selection2.select(".loginLogout");
-      if (user) {
-        userInfo.html("").classed("hide", false);
-        let userLink = userInfo.append("a").attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
-        if (user.image_url) {
-          userLink.append("img").attr("class", "icon pre-text user-icon").attr("src", user.image_url);
-        } else {
-          userLink.call(svgIcon("#iD-icon-avatar", "pre-text light"));
-        }
-        userLink.append("span").attr("class", "label").html(user.display_name);
-        loginLogout.classed("hide", false).select("a").text(_t("logout")).on("click", (e) => {
-          e.preventDefault();
-          osm.logout();
-          tryLogout();
-        });
-      } else {
-        userInfo.html("").classed("hide", true);
-        loginLogout.classed("hide", false).select("a").text(_t("login")).on("click", (e) => {
-          e.preventDefault();
-          osm.authenticate();
-        });
+    function editOn() {
+      if (!layerVisible) {
+        layerVisible = true;
+        drawLayer.style("display", "block");
       }
     }
-    function tryLogout() {
-      if (!osm)
-        return;
-      const url = osm.getUrlRoot() + "/logout?referer=%2Flogin";
-      const w = 600;
-      const h = 550;
-      const settings = [
-        ["width", w],
-        ["height", h],
-        ["left", window.screen.width / 2 - w / 2],
-        ["top", window.screen.height / 2 - h / 2]
-      ].map((x) => x.join("=")).join(",");
-      window.open(url, "_blank", settings);
+    function editOff() {
+      if (layerVisible) {
+        layerVisible = false;
+        drawLayer.style("display", "none");
+        drawLayer.selectAll(".qaItem.keepRight").remove();
+        touchLayer.selectAll(".qaItem.keepRight").remove();
+      }
     }
-    return function(selection2) {
-      if (!osm)
-        return;
-      selection2.append("li").attr("class", "userInfo").classed("hide", true);
-      selection2.append("li").attr("class", "loginLogout").classed("hide", true).append("a").attr("href", "#");
-      osm.on("change.account", () => updateUserDetails(selection2));
-      updateUserDetails(selection2);
-    };
-  }
-
-  // modules/ui/attribution.js
-  function uiAttribution(context) {
-    let _selection = select_default2(null);
-    function render(selection2, data, klass) {
-      let div = selection2.selectAll(`.${klass}`).data([0]);
-      div = div.enter().append("div").attr("class", klass).merge(div);
-      let attributions = div.selectAll(".attribution").data(data, (d) => d.id);
-      attributions.exit().remove();
-      attributions = attributions.enter().append("span").attr("class", "attribution").each((d, i2, nodes) => {
-        let attribution = select_default2(nodes[i2]);
-        if (d.terms_html) {
-          attribution.html(d.terms_html);
-          return;
-        }
-        if (d.terms_url) {
-          attribution = attribution.append("a").attr("href", d.terms_url).attr("target", "_blank");
-        }
-        const sourceID = d.id.replace(/\./g, "<TX_DOT>");
-        const terms_text = _t(
-          `imagery.${sourceID}.attribution.text`,
-          { default: d.terms_text || d.id || d.name() }
-        );
-        if (d.icon && !d.overlay) {
-          attribution.append("img").attr("class", "source-image").attr("src", d.icon);
-        }
-        attribution.append("span").attr("class", "attribution-text").text(terms_text);
-      }).merge(attributions);
-      let copyright = attributions.selectAll(".copyright-notice").data((d) => {
-        let notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
-        return notice ? [notice] : [];
+    function layerOn() {
+      editOn();
+      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", () => dispatch14.call("change"));
+    }
+    function layerOff() {
+      throttledRedraw.cancel();
+      drawLayer.interrupt();
+      touchLayer.selectAll(".qaItem.keepRight").remove();
+      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", () => {
+        editOff();
+        dispatch14.call("change");
       });
-      copyright.exit().remove();
-      copyright = copyright.enter().append("span").attr("class", "copyright-notice").merge(copyright);
-      copyright.text(String);
     }
-    function update() {
-      let baselayer = context.background().baseLayerSource();
-      _selection.call(render, baselayer ? [baselayer] : [], "base-layer-attribution");
-      const z = context.map().zoom();
-      let overlays = context.background().overlayLayerSources() || [];
-      _selection.call(render, overlays.filter((s) => s.validZoom(z)), "overlay-layer-attribution");
+    function updateMarkers() {
+      if (!layerVisible || !_layerEnabled) return;
+      const service = getService();
+      const selectedID = context.selectedErrorID();
+      const data = service ? service.getItems(projection2) : [];
+      const getTransform = svgPointTransform(projection2);
+      const markers = drawLayer.selectAll(".qaItem.keepRight").data(data, (d2) => d2.id);
+      markers.exit().remove();
+      const markersEnter = markers.enter().append("g").attr("class", (d2) => "qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.parentIssueType));
+      markersEnter.append("ellipse").attr("cx", 0.5).attr("cy", 1).attr("rx", 6.5).attr("ry", 3).attr("class", "stroke");
+      markersEnter.append("path").call(markerPath, "shadow");
+      markersEnter.append("use").attr("class", "qaItem-fill").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").attr("xlink:href", "#iD-icon-bolt");
+      markers.merge(markersEnter).sort(sortY).classed("selected", (d2) => d2.id === selectedID).attr("transform", getTransform);
+      if (touchLayer.empty()) return;
+      const fillClass = context.getDebug("target") ? "pink " : "nocolor ";
+      const targets = touchLayer.selectAll(".qaItem.keepRight").data(data, (d2) => d2.id);
+      targets.exit().remove();
+      targets.enter().append("rect").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").merge(targets).sort(sortY).attr("class", (d2) => "qaItem ".concat(d2.service, " target ").concat(fillClass, " itemId-").concat(d2.id)).attr("transform", getTransform);
+      function sortY(a2, b2) {
+        return a2.id === selectedID ? 1 : b2.id === selectedID ? -1 : a2.severity === "error" && b2.severity !== "error" ? 1 : b2.severity === "error" && a2.severity !== "error" ? -1 : b2.loc[1] - a2.loc[1];
+      }
     }
-    return function(selection2) {
-      _selection = selection2;
-      context.background().on("change.attribution", update);
-      context.map().on("move.attribution", throttle_default(update, 400, { leading: false }));
-      update();
-    };
-  }
-
-  // modules/ui/contributors.js
-  function uiContributors(context) {
-    var osm = context.connection(), debouncedUpdate = debounce_default(function() {
-      update();
-    }, 1e3), limit = 4, hidden = false, wrap2 = select_default2(null);
-    function update() {
-      if (!osm)
-        return;
-      var users = {}, entities = context.history().intersects(context.map().extent());
-      entities.forEach(function(entity) {
-        if (entity && entity.user)
-          users[entity.user] = true;
-      });
-      var u = Object.keys(users), subset = u.slice(0, u.length > limit ? limit - 1 : limit);
-      wrap2.html("").call(svgIcon("#iD-icon-nearby", "pre-text light"));
-      var userList = select_default2(document.createElement("span"));
-      userList.selectAll().data(subset).enter().append("a").attr("class", "user-link").attr("href", function(d) {
-        return osm.userURL(d);
-      }).attr("target", "_blank").text(String);
-      if (u.length > limit) {
-        var count = select_default2(document.createElement("span"));
-        var othersNum = u.length - limit + 1;
-        count.append("a").attr("target", "_blank").attr("href", function() {
-          return osm.changesetsURL(context.map().center(), context.map().zoom());
-        }).text(othersNum);
-        wrap2.append("span").html(_t.html("contributors.truncated_list", { n: othersNum, users: { html: userList.html() }, count: { html: count.html() } }));
-      } else {
-        wrap2.append("span").html(_t.html("contributors.list", { users: { html: userList.html() } }));
+    function drawKeepRight(selection2) {
+      const service = getService();
+      const surface = context.surface();
+      if (surface && !surface.empty()) {
+        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
       }
-      if (!u.length) {
-        hidden = true;
-        wrap2.transition().style("opacity", 0);
-      } else if (hidden) {
-        wrap2.transition().style("opacity", 1);
+      drawLayer = selection2.selectAll(".layer-keepRight").data(service ? [0] : []);
+      drawLayer.exit().remove();
+      drawLayer = drawLayer.enter().append("g").attr("class", "layer-keepRight").style("display", _layerEnabled ? "block" : "none").merge(drawLayer);
+      if (_layerEnabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          service.loadIssues(projection2);
+          updateMarkers();
+        } else {
+          editOff();
+        }
       }
     }
-    return function(selection2) {
-      if (!osm)
-        return;
-      wrap2 = selection2;
-      update();
-      osm.on("loaded.contributors", debouncedUpdate);
-      context.map().on("move.contributors", debouncedUpdate);
-    };
-  }
-
-  // modules/ui/popover.js
-  var _popoverID = 0;
-  function uiPopover(klass) {
-    var _id = _popoverID++;
-    var _anchorSelection = select_default2(null);
-    var popover = function(selection2) {
-      _anchorSelection = selection2;
-      selection2.each(setup);
-    };
-    var _animation = utilFunctor(false);
-    var _placement = utilFunctor("top");
-    var _alignment = utilFunctor("center");
-    var _scrollContainer = utilFunctor(select_default2(null));
-    var _content;
-    var _displayType = utilFunctor("");
-    var _hasArrow = utilFunctor(true);
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    popover.displayType = function(val) {
-      if (arguments.length) {
-        _displayType = utilFunctor(val);
-        return popover;
+    drawKeepRight.enabled = function(val) {
+      if (!arguments.length) return _layerEnabled;
+      _layerEnabled = val;
+      if (_layerEnabled) {
+        layerOn();
       } else {
-        return _displayType;
+        layerOff();
+        if (context.selectedErrorID()) {
+          context.enter(modeBrowse(context));
+        }
       }
+      dispatch14.call("change");
+      return this;
     };
-    popover.hasArrow = function(val) {
-      if (arguments.length) {
-        _hasArrow = utilFunctor(val);
-        return popover;
+    drawKeepRight.supported = () => !!getService();
+    return drawKeepRight;
+  }
+
+  // modules/svg/geolocate.js
+  function svgGeolocate(projection2) {
+    var layer = select_default2(null);
+    var _position;
+    function init2() {
+      if (svgGeolocate.initialized) return;
+      svgGeolocate.enabled = false;
+      svgGeolocate.initialized = true;
+    }
+    function showLayer() {
+      layer.style("display", "block");
+    }
+    function hideLayer() {
+      layer.transition().duration(250).style("opacity", 0);
+    }
+    function layerOn() {
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1);
+    }
+    function layerOff() {
+      layer.style("display", "none");
+    }
+    function transform2(d2) {
+      return svgPointTransform(projection2)(d2);
+    }
+    function accuracy(accuracy2, loc) {
+      var degreesRadius = geoMetersToLat(accuracy2), tangentLoc = [loc[0], loc[1] + degreesRadius], projectedTangent = projection2(tangentLoc), projectedLoc = projection2([loc[0], loc[1]]);
+      return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
+    }
+    function update() {
+      var geolocation = { loc: [_position.coords.longitude, _position.coords.latitude] };
+      var groups = layer.selectAll(".geolocations").selectAll(".geolocation").data([geolocation]);
+      groups.exit().remove();
+      var pointsEnter = groups.enter().append("g").attr("class", "geolocation");
+      pointsEnter.append("circle").attr("class", "geolocate-radius").attr("dx", "0").attr("dy", "0").attr("fill", "rgb(15,128,225)").attr("fill-opacity", "0.3").attr("r", "0");
+      pointsEnter.append("circle").attr("dx", "0").attr("dy", "0").attr("fill", "rgb(15,128,225)").attr("stroke", "white").attr("stroke-width", "1.5").attr("r", "6");
+      groups.merge(pointsEnter).attr("transform", transform2);
+      layer.select(".geolocate-radius").attr("r", accuracy(_position.coords.accuracy, geolocation.loc));
+    }
+    function drawLocation(selection2) {
+      var enabled = svgGeolocate.enabled;
+      layer = selection2.selectAll(".layer-geolocate").data([0]);
+      layer.exit().remove();
+      var layerEnter = layer.enter().append("g").attr("class", "layer-geolocate").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "geolocations");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        update();
       } else {
-        return _hasArrow;
+        layerOff();
       }
-    };
-    popover.placement = function(val) {
-      if (arguments.length) {
-        _placement = utilFunctor(val);
-        return popover;
+    }
+    drawLocation.enabled = function(position, enabled) {
+      if (!arguments.length) return svgGeolocate.enabled;
+      _position = position;
+      svgGeolocate.enabled = enabled;
+      if (svgGeolocate.enabled) {
+        showLayer();
+        layerOn();
       } else {
-        return _placement;
+        hideLayer();
       }
+      return this;
     };
-    popover.alignment = function(val) {
-      if (arguments.length) {
-        _alignment = utilFunctor(val);
-        return popover;
+    init2();
+    return drawLocation;
+  }
+
+  // modules/svg/labels.js
+  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 RBush();
+    var _rskipped = new RBush();
+    var _textWidthCache = {};
+    var _entitybboxes = {};
+    var labelStack = [
+      ["line", "aeroway", "*", 12],
+      ["line", "highway", "motorway", 12],
+      ["line", "highway", "trunk", 12],
+      ["line", "highway", "primary", 12],
+      ["line", "highway", "secondary", 12],
+      ["line", "highway", "tertiary", 12],
+      ["line", "highway", "*", 12],
+      ["line", "railway", "*", 12],
+      ["line", "waterway", "*", 12],
+      ["area", "aeroway", "*", 12],
+      ["area", "amenity", "*", 12],
+      ["area", "building", "*", 12],
+      ["area", "historic", "*", 12],
+      ["area", "leisure", "*", 12],
+      ["area", "man_made", "*", 12],
+      ["area", "natural", "*", 12],
+      ["area", "shop", "*", 12],
+      ["area", "tourism", "*", 12],
+      ["area", "camp_site", "*", 12],
+      ["point", "aeroway", "*", 10],
+      ["point", "amenity", "*", 10],
+      ["point", "building", "*", 10],
+      ["point", "historic", "*", 10],
+      ["point", "leisure", "*", 10],
+      ["point", "man_made", "*", 10],
+      ["point", "natural", "*", 10],
+      ["point", "shop", "*", 10],
+      ["point", "tourism", "*", 10],
+      ["point", "camp_site", "*", 10],
+      ["line", "ref", "*", 12],
+      ["area", "ref", "*", 12],
+      ["point", "ref", "*", 10],
+      ["line", "name", "*", 12],
+      ["area", "name", "*", 12],
+      ["point", "name", "*", 10]
+    ];
+    function shouldSkipIcon(preset) {
+      var noIcons = ["building", "landuse", "natural"];
+      return noIcons.some(function(s2) {
+        return preset.id.indexOf(s2) >= 0;
+      });
+    }
+    function get4(array2, prop) {
+      return function(d2, i3) {
+        return array2[i3][prop];
+      };
+    }
+    function textWidth(text, size, elem) {
+      var c2 = _textWidthCache[size];
+      if (!c2) c2 = _textWidthCache[size] = {};
+      if (c2[text]) {
+        return c2[text];
+      } else if (elem) {
+        c2[text] = elem.getComputedTextLength();
+        return c2[text];
       } else {
-        return _alignment;
+        var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
+        if (str === null) {
+          return size / 3 * 2 * text.length;
+        } else {
+          return size / 3 * (2 * text.length + str.length);
+        }
       }
-    };
-    popover.scrollContainer = function(val) {
-      if (arguments.length) {
-        _scrollContainer = utilFunctor(val);
-        return popover;
-      } else {
-        return _scrollContainer;
-      }
-    };
-    popover.content = function(val) {
-      if (arguments.length) {
-        _content = val;
-        return popover;
-      } else {
-        return _content;
-      }
-    };
-    popover.isShown = function() {
-      var popoverSelection = _anchorSelection.select(".popover-" + _id);
-      return !popoverSelection.empty() && popoverSelection.classed("in");
-    };
-    popover.show = function() {
-      _anchorSelection.each(show);
-    };
-    popover.updateContent = function() {
-      _anchorSelection.each(updateContent);
-    };
-    popover.hide = function() {
-      _anchorSelection.each(hide);
-    };
-    popover.toggle = function() {
-      _anchorSelection.each(toggle);
-    };
-    popover.destroy = function(selection2, selector) {
-      selector = selector || ".popover-" + _id;
-      selection2.on(_pointerPrefix + "enter.popover", null).on(_pointerPrefix + "leave.popover", null).on(_pointerPrefix + "up.popover", null).on(_pointerPrefix + "down.popover", null).on("click.popover", null).attr("title", function() {
-        return this.getAttribute("data-original-title") || this.getAttribute("title");
-      }).attr("data-original-title", null).selectAll(selector).remove();
-    };
-    popover.destroyAny = function(selection2) {
-      selection2.call(popover.destroy, ".popover");
-    };
-    function setup() {
-      var anchor = select_default2(this);
-      var animate = _animation.apply(this, arguments);
-      var popoverSelection = anchor.selectAll(".popover-" + _id).data([0]);
-      var enter = popoverSelection.enter().append("div").attr("class", "popover popover-" + _id + " " + (klass ? klass : "")).classed("arrowed", _hasArrow.apply(this, arguments));
-      enter.append("div").attr("class", "popover-arrow");
-      enter.append("div").attr("class", "popover-inner");
-      popoverSelection = enter.merge(popoverSelection);
-      if (animate) {
-        popoverSelection.classed("fade", true);
-      }
-      var display = _displayType.apply(this, arguments);
-      if (display === "hover") {
-        var _lastNonMouseEnterTime;
-        anchor.on(_pointerPrefix + "enter.popover", function(d3_event) {
-          if (d3_event.pointerType) {
-            if (d3_event.pointerType !== "mouse") {
-              _lastNonMouseEnterTime = d3_event.timeStamp;
-              return;
-            } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
-              return;
-            }
-          }
-          if (d3_event.buttons !== 0)
-            return;
-          show.apply(this, arguments);
-        }).on(_pointerPrefix + "leave.popover", function() {
-          hide.apply(this, arguments);
-        }).on("focus.popover", function() {
-          show.apply(this, arguments);
-        }).on("blur.popover", function() {
-          hide.apply(this, arguments);
-        });
-      } else if (display === "clickFocus") {
-        anchor.on(_pointerPrefix + "down.popover", function(d3_event) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-        }).on(_pointerPrefix + "up.popover", function(d3_event) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-        }).on("click.popover", toggle);
-        popoverSelection.attr("tabindex", 0).on("blur.popover", function() {
-          anchor.each(function() {
-            hide.apply(this, arguments);
-          });
-        });
-      }
-    }
-    function show() {
-      var anchor = select_default2(this);
-      var popoverSelection = anchor.selectAll(".popover-" + _id);
-      if (popoverSelection.empty()) {
-        anchor.call(popover.destroy);
-        anchor.each(setup);
-        popoverSelection = anchor.selectAll(".popover-" + _id);
-      }
-      popoverSelection.classed("in", true);
-      var displayType = _displayType.apply(this, arguments);
-      if (displayType === "clickFocus") {
-        anchor.classed("active", true);
-        popoverSelection.node().focus();
-      }
-      anchor.each(updateContent);
     }
-    function updateContent() {
-      var anchor = select_default2(this);
-      if (_content) {
-        anchor.selectAll(".popover-" + _id + " > .popover-inner").call(_content.apply(this, arguments));
-      }
-      updatePosition.apply(this, arguments);
-      updatePosition.apply(this, arguments);
-      updatePosition.apply(this, arguments);
+    function drawLinePaths(selection2, entities, filter2, classes, labels) {
+      var paths = selection2.selectAll("path").filter(filter2).data(entities, osmEntity.key);
+      paths.exit().remove();
+      paths.enter().append("path").style("stroke-width", get4(labels, "font-size")).attr("id", function(d2) {
+        return "ideditor-labelpath-" + d2.id;
+      }).attr("class", classes).merge(paths).attr("d", get4(labels, "lineString"));
     }
-    function updatePosition() {
-      var anchor = select_default2(this);
-      var popoverSelection = anchor.selectAll(".popover-" + _id);
-      var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
-      var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
-      var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
-      var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
-      var placement = _placement.apply(this, arguments);
-      popoverSelection.classed("left", false).classed("right", false).classed("top", false).classed("bottom", false).classed(placement, true);
-      var alignment = _alignment.apply(this, arguments);
-      var alignFactor = 0.5;
-      if (alignment === "leading") {
-        alignFactor = 0;
-      } else if (alignment === "trailing") {
-        alignFactor = 1;
-      }
-      var anchorFrame = getFrame(anchor.node());
-      var popoverFrame = getFrame(popoverSelection.node());
-      var position;
-      switch (placement) {
-        case "top":
-          position = {
-            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
-            y: anchorFrame.y - popoverFrame.h
-          };
-          break;
-        case "bottom":
-          position = {
-            x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
-            y: anchorFrame.y + anchorFrame.h
-          };
-          break;
-        case "left":
-          position = {
-            x: anchorFrame.x - popoverFrame.w,
-            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
-          };
-          break;
-        case "right":
-          position = {
-            x: anchorFrame.x + anchorFrame.w,
-            y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
-          };
-          break;
-      }
-      if (position) {
-        if (scrollNode && (placement === "top" || placement === "bottom")) {
-          var initialPosX = position.x;
-          if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
-            position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
-          } else if (position.x < 10) {
-            position.x = 10;
-          }
-          var arrow = anchor.selectAll(".popover-" + _id + " > .popover-arrow");
-          var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
-          arrow.style("left", ~~arrowPosX + "px");
-        }
-        popoverSelection.style("left", ~~position.x + "px").style("top", ~~position.y + "px");
-      } else {
-        popoverSelection.style("left", null).style("top", null);
-      }
-      function getFrame(node) {
-        var positionStyle = select_default2(node).style("position");
-        if (positionStyle === "absolute" || positionStyle === "static") {
-          return {
-            x: node.offsetLeft - scrollLeft,
-            y: node.offsetTop - scrollTop,
-            w: node.offsetWidth,
-            h: node.offsetHeight
-          };
-        } else {
-          return {
-            x: 0,
-            y: 0,
-            w: node.offsetWidth,
-            h: node.offsetHeight
-          };
-        }
-      }
+    function drawLineLabels(selection2, entities, filter2, classes, labels) {
+      var texts = selection2.selectAll("text." + classes).filter(filter2).data(entities, osmEntity.key);
+      texts.exit().remove();
+      texts.enter().append("text").attr("class", function(d2, i3) {
+        return classes + " " + labels[i3].classes + " " + d2.id;
+      }).attr("dy", baselineHack ? "0.35em" : null).append("textPath").attr("class", "textpath");
+      selection2.selectAll("text." + classes).selectAll(".textpath").filter(filter2).data(entities, osmEntity.key).attr("startOffset", "50%").attr("xlink:href", function(d2) {
+        return "#ideditor-labelpath-" + d2.id;
+      }).text(utilDisplayNameForPath);
     }
-    function hide() {
-      var anchor = select_default2(this);
-      if (_displayType.apply(this, arguments) === "clickFocus") {
-        anchor.classed("active", false);
-      }
-      anchor.selectAll(".popover-" + _id).classed("in", false);
+    function drawPointLabels(selection2, entities, filter2, classes, labels) {
+      var texts = selection2.selectAll("text." + classes).filter(filter2).data(entities, osmEntity.key);
+      texts.exit().remove();
+      texts.enter().append("text").attr("class", function(d2, i3) {
+        return classes + " " + labels[i3].classes + " " + d2.id;
+      }).merge(texts).attr("x", get4(labels, "x")).attr("y", get4(labels, "y")).style("text-anchor", get4(labels, "textAnchor")).text(utilDisplayName).each(function(d2, i3) {
+        textWidth(utilDisplayName(d2), labels[i3].height, this);
+      });
     }
-    function toggle() {
-      if (select_default2(this).select(".popover-" + _id).classed("in")) {
-        hide.apply(this, arguments);
-      } else {
-        show.apply(this, arguments);
+    function drawAreaLabels(selection2, entities, filter2, classes, labels) {
+      entities = entities.filter(hasText);
+      labels = labels.filter(hasText);
+      drawPointLabels(selection2, entities, filter2, classes, labels);
+      function hasText(d2, i3) {
+        return labels[i3].hasOwnProperty("x") && labels[i3].hasOwnProperty("y");
       }
     }
-    return popover;
-  }
-
-  // modules/ui/tooltip.js
-  function uiTooltip(klass) {
-    var tooltip = uiPopover((klass || "") + " tooltip").displayType("hover");
-    var _title = function() {
-      var title = this.getAttribute("data-original-title");
-      if (title) {
-        return title;
-      } else {
-        title = this.getAttribute("title");
-        this.removeAttribute("title");
-        this.setAttribute("data-original-title", title);
-      }
-      return title;
-    };
-    var _heading = utilFunctor(null);
-    var _keys = utilFunctor(null);
-    tooltip.title = function(val) {
-      if (!arguments.length)
-        return _title;
-      _title = utilFunctor(val);
-      return tooltip;
-    };
-    tooltip.heading = function(val) {
-      if (!arguments.length)
-        return _heading;
-      _heading = utilFunctor(val);
-      return tooltip;
-    };
-    tooltip.keys = function(val) {
-      if (!arguments.length)
-        return _keys;
-      _keys = utilFunctor(val);
-      return tooltip;
-    };
-    tooltip.content(function() {
-      var heading = _heading.apply(this, arguments);
-      var text2 = _title.apply(this, arguments);
-      var keys = _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) {
-        var headingSelect = selection2.selectAll(".tooltip-heading").data(heading ? [heading] : []);
-        headingSelect.exit().remove();
-        headingSelect.enter().append("div").attr("class", "tooltip-heading").merge(headingSelect).text("").call(headingCallback);
-        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] : []);
-        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) {
-          return d;
-        });
-      };
-    });
-    return tooltip;
-  }
-
-  // modules/ui/edit_menu.js
-  function uiEditMenu(context) {
-    var dispatch10 = dispatch_default("toggled");
-    var _menu = select_default2(null);
-    var _operations = [];
-    var _anchorLoc = [0, 0];
-    var _anchorLocLonLat = [0, 0];
-    var _triggerType = "";
-    var _vpTopMargin = 85;
-    var _vpBottomMargin = 45;
-    var _vpSideMargin = 35;
-    var _menuTop = false;
-    var _menuHeight;
-    var _menuWidth;
-    var _verticalPadding = 4;
-    var _tooltipWidth = 210;
-    var _menuSideMargin = 10;
-    var _tooltips = [];
-    var editMenu = function(selection2) {
-      var isTouchMenu = _triggerType.includes("touch") || _triggerType.includes("pen");
-      var ops = _operations.filter(function(op) {
-        return !isTouchMenu || !op.mouseOnly;
-      });
-      if (!ops.length)
-        return;
-      _tooltips = [];
-      _menuTop = isTouchMenu;
-      var showLabels = isTouchMenu;
-      var buttonHeight = showLabels ? 32 : 34;
-      if (showLabels) {
-        _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function(op) {
-          return op.title.length;
-        })));
-      } else {
-        _menuWidth = 44;
-      }
-      _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
-      _menu = selection2.append("div").attr("class", "edit-menu").classed("touch-menu", isTouchMenu).style("padding", _verticalPadding + "px 0");
-      var buttons = _menu.selectAll(".edit-menu-item").data(ops);
-      var buttonsEnter = buttons.enter().append("button").attr("class", function(d) {
-        return "edit-menu-item edit-menu-item-" + d.id;
-      }).style("height", buttonHeight + "px").on("click", click).on("pointerup", pointerup).on("pointerdown mousedown", function pointerdown(d3_event) {
-        d3_event.stopPropagation();
-      }).on("mouseenter.highlight", function(d3_event, d) {
-        if (!d.relatedEntityIds || select_default2(this).classed("disabled"))
-          return;
-        utilHighlightEntities(d.relatedEntityIds(), true, context);
-      }).on("mouseleave.highlight", function(d3_event, d) {
-        if (!d.relatedEntityIds)
-          return;
-        utilHighlightEntities(d.relatedEntityIds(), false, context);
-      });
-      buttonsEnter.each(function(d) {
-        var tooltip = uiTooltip().heading(() => d.title).title(d.tooltip).keys([d.keys[0]]);
-        _tooltips.push(tooltip);
-        select_default2(this).call(tooltip).append("div").attr("class", "icon-wrap").call(svgIcon(d.icon && d.icon() || "#iD-operation-" + d.id, "operation"));
+    function drawAreaIcons(selection2, entities, filter2, classes, labels) {
+      var icons = selection2.selectAll("use." + classes).filter(filter2).data(entities, osmEntity.key);
+      icons.exit().remove();
+      icons.enter().append("use").attr("class", "icon " + classes).attr("width", "17px").attr("height", "17px").merge(icons).attr("transform", get4(labels, "transform")).attr("xlink:href", function(d2) {
+        var preset = _mainPresetIndex.match(d2, context.graph());
+        var picon = preset && preset.icon;
+        return picon ? "#" + picon : "";
       });
-      if (showLabels) {
-        buttonsEnter.append("span").attr("class", "label").html(function(d) {
-          return d.title;
+    }
+    function drawCollisionBoxes(selection2, rtree, which) {
+      var classes = "debug " + which + " " + (which === "debug-skipped" ? "orange" : "yellow");
+      var gj = [];
+      if (context.getDebug("collision")) {
+        gj = rtree.all().map(function(d2) {
+          return { type: "Polygon", coordinates: [[
+            [d2.minX, d2.minY],
+            [d2.maxX, d2.minY],
+            [d2.maxX, d2.maxY],
+            [d2.minX, d2.maxY],
+            [d2.minX, d2.minY]
+          ]] };
         });
       }
-      buttonsEnter.merge(buttons).classed("disabled", function(d) {
-        return d.disabled();
-      });
-      updatePosition();
-      var initialScale = context.projection.scale();
-      context.map().on("move.edit-menu", function() {
-        if (initialScale !== context.projection.scale()) {
-          editMenu.close();
-        }
-      }).on("drawn.edit-menu", function(info) {
-        if (info.full)
-          updatePosition();
-      });
-      var lastPointerUpType;
-      function pointerup(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
+      var boxes = selection2.selectAll("." + which).data(gj);
+      boxes.exit().remove();
+      boxes.enter().append("path").attr("class", classes).merge(boxes).attr("d", path_default());
+    }
+    function drawLabels(selection2, graph, entities, filter2, dimensions, fullRedraw) {
+      var wireframe = context.surface().classed("fill-wireframe");
+      var zoom = geoScaleToZoom(projection2.scale());
+      var labelable = [];
+      var renderNodeAs = {};
+      var i3, j2, k2, entity, geometry;
+      for (i3 = 0; i3 < labelStack.length; i3++) {
+        labelable.push([]);
       }
-      function click(d3_event, operation) {
-        d3_event.stopPropagation();
-        if (operation.relatedEntityIds) {
-          utilHighlightEntities(operation.relatedEntityIds(), false, context);
-        }
-        if (operation.disabled()) {
-          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
-            context.ui().flash.duration(4e3).iconName("#iD-operation-" + operation.id).iconClass("operation disabled").label(operation.tooltip())();
-          }
-        } else {
-          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
-            context.ui().flash.duration(2e3).iconName("#iD-operation-" + operation.id).iconClass("operation").label(operation.annotation() || operation.title)();
+      if (fullRedraw) {
+        _rdrawn.clear();
+        _rskipped.clear();
+        _entitybboxes = {};
+      } else {
+        for (i3 = 0; i3 < entities.length; i3++) {
+          entity = entities[i3];
+          var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + "I"] || []);
+          for (j2 = 0; j2 < toRemove.length; j2++) {
+            _rdrawn.remove(toRemove[j2]);
+            _rskipped.remove(toRemove[j2]);
           }
-          operation();
-          editMenu.close();
         }
-        lastPointerUpType = null;
-      }
-      dispatch10.call("toggled", this, true);
-    };
-    function updatePosition() {
-      if (!_menu || _menu.empty())
-        return;
-      var anchorLoc = context.projection(_anchorLocLonLat);
-      var viewport = context.surfaceRect();
-      if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
-        editMenu.close();
-        return;
       }
-      var menuLeft = displayOnLeft(viewport);
-      var offset = [0, 0];
-      offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
-      if (_menuTop) {
-        if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
-          offset[1] = -anchorLoc[1] + _vpTopMargin;
-        } else {
-          offset[1] = -_menuHeight;
+      for (i3 = 0; i3 < entities.length; i3++) {
+        entity = entities[i3];
+        geometry = entity.geometry(graph);
+        if (geometry === "point" || geometry === "vertex" && isInterestingVertex(entity)) {
+          var hasDirections = entity.directions(graph, projection2).length;
+          var markerPadding;
+          if (!wireframe && geometry === "point" && !(zoom >= 18 && hasDirections)) {
+            renderNodeAs[entity.id] = "point";
+            markerPadding = 20;
+          } else {
+            renderNodeAs[entity.id] = "vertex";
+            markerPadding = 0;
+          }
+          var coord2 = projection2(entity.loc);
+          var nodePadding = 10;
+          var bbox2 = {
+            minX: coord2[0] - nodePadding,
+            minY: coord2[1] - nodePadding - markerPadding,
+            maxX: coord2[0] + nodePadding,
+            maxY: coord2[1] + nodePadding
+          };
+          doInsert(bbox2, entity.id + "P");
         }
-      } else {
-        if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
-          offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
-        } else {
-          offset[1] = 0;
+        if (geometry === "vertex") {
+          geometry = "point";
         }
-      }
-      var origin = geoVecAdd(anchorLoc, offset);
-      _menu.style("left", origin[0] + "px").style("top", origin[1] + "px");
-      var tooltipSide = tooltipPosition(viewport, menuLeft);
-      _tooltips.forEach(function(tooltip) {
-        tooltip.placement(tooltipSide);
-      });
-      function displayOnLeft(viewport2) {
-        if (_mainLocalizer.textDirection() === "ltr") {
-          if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport2.width - _vpSideMargin) {
-            return true;
-          }
-          return false;
-        } else {
-          if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
-            return false;
+        var preset = geometry === "area" && _mainPresetIndex.match(entity, graph);
+        var icon2 = preset && !shouldSkipIcon(preset) && preset.icon;
+        if (!icon2 && !utilDisplayName(entity)) continue;
+        for (k2 = 0; k2 < labelStack.length; k2++) {
+          var matchGeom = labelStack[k2][0];
+          var matchKey = labelStack[k2][1];
+          var matchVal = labelStack[k2][2];
+          var hasVal = entity.tags[matchKey];
+          if (geometry === matchGeom && hasVal && (matchVal === "*" || matchVal === hasVal)) {
+            labelable[k2].push(entity);
+            break;
           }
-          return true;
         }
       }
-      function tooltipPosition(viewport2, menuLeft2) {
-        if (_mainLocalizer.textDirection() === "ltr") {
-          if (menuLeft2) {
-            return "left";
-          }
-          if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport2.width - _vpSideMargin) {
-            return "left";
-          }
-          return "right";
-        } else {
-          if (!menuLeft2) {
-            return "right";
+      var positions = {
+        point: [],
+        line: [],
+        area: []
+      };
+      var labelled = {
+        point: [],
+        line: [],
+        area: []
+      };
+      for (k2 = 0; k2 < labelable.length; k2++) {
+        var fontSize = labelStack[k2][3];
+        for (i3 = 0; i3 < labelable[k2].length; i3++) {
+          entity = labelable[k2][i3];
+          geometry = entity.geometry(graph);
+          var getName = geometry === "line" ? utilDisplayNameForPath : utilDisplayName;
+          var name = getName(entity);
+          var width = name && textWidth(name, fontSize);
+          var p2 = null;
+          if (geometry === "point" || geometry === "vertex") {
+            if (wireframe) continue;
+            var renderAs = renderNodeAs[entity.id];
+            if (renderAs === "vertex" && zoom < 17) continue;
+            p2 = getPointLabel(entity, width, fontSize, renderAs);
+          } else if (geometry === "line") {
+            p2 = getLineLabel(entity, width, fontSize);
+          } else if (geometry === "area") {
+            p2 = getAreaLabel(entity, width, fontSize);
           }
-          if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
-            return "right";
+          if (p2) {
+            if (geometry === "vertex") {
+              geometry = "point";
+            }
+            p2.classes = geometry + " tag-" + labelStack[k2][1];
+            positions[geometry].push(p2);
+            labelled[geometry].push(entity);
           }
-          return "left";
         }
       }
-    }
-    editMenu.close = function() {
-      context.map().on("move.edit-menu", null).on("drawn.edit-menu", null);
-      _menu.remove();
-      _tooltips = [];
-      dispatch10.call("toggled", this, false);
-    };
-    editMenu.anchorLoc = function(val) {
-      if (!arguments.length)
-        return _anchorLoc;
-      _anchorLoc = val;
-      _anchorLocLonLat = context.projection.invert(_anchorLoc);
-      return editMenu;
-    };
-    editMenu.triggerType = function(val) {
-      if (!arguments.length)
-        return _triggerType;
-      _triggerType = val;
-      return editMenu;
-    };
-    editMenu.operations = function(val) {
-      if (!arguments.length)
-        return _operations;
-      _operations = val;
-      return editMenu;
-    };
-    return utilRebind(editMenu, dispatch10, "on");
-  }
-
-  // modules/ui/feature_info.js
-  function uiFeatureInfo(context) {
-    function update(selection2) {
-      var features2 = context.features();
-      var stats = features2.stats();
-      var count = 0;
-      var hiddenList = features2.hidden().map(function(k) {
-        if (stats[k]) {
-          count += stats[k];
-          return _t.append("inspector.title_count", {
-            title: _t("feature." + k + ".description"),
-            count: stats[k]
-          });
-        }
-        return null;
-      }).filter(Boolean);
-      selection2.text("");
-      if (hiddenList.length) {
-        var tooltipBehavior = uiTooltip().placement("top").title(function() {
-          return (selection3) => {
-            hiddenList.forEach((hiddenFeature) => {
-              selection3.append("div").call(hiddenFeature);
-            });
-          };
-        });
-        selection2.append("a").attr("class", "chip").attr("href", "#").call(_t.append("feature_info.hidden_warning", { count })).call(tooltipBehavior).on("click", function(d3_event) {
-          tooltipBehavior.hide();
-          d3_event.preventDefault();
-          context.ui().togglePanes(context.container().select(".map-panes .map-data-pane"));
+      function isInterestingVertex(entity2) {
+        var selectedIDs = context.selectedIDs();
+        return entity2.hasInterestingTags() || entity2.isEndpoint(graph) || entity2.isConnected(graph) || selectedIDs.indexOf(entity2.id) !== -1 || graph.parentWays(entity2).some(function(parent) {
+          return selectedIDs.indexOf(parent.id) !== -1;
         });
       }
-      selection2.classed("hide", !hiddenList.length);
-    }
-    return function(selection2) {
-      update(selection2);
-      context.features().on("change.feature_info", function() {
-        update(selection2);
-      });
-    };
-  }
-
-  // modules/ui/flash.js
-  function uiFlash(context) {
-    var _flashTimer;
-    var _duration = 2e3;
-    var _iconName = "#iD-icon-no";
-    var _iconClass = "disabled";
-    var _label = (s) => s.text("");
-    function flash() {
-      if (_flashTimer) {
-        _flashTimer.stop();
+      function getPointLabel(entity2, width2, height, geometry2) {
+        var y2 = geometry2 === "point" ? -12 : 0;
+        var pointOffsets = {
+          ltr: [15, y2, "start"],
+          rtl: [-15, y2, "end"]
+        };
+        var textDirection = _mainLocalizer.textDirection();
+        var coord3 = projection2(entity2.loc);
+        var textPadding = 2;
+        var offset = pointOffsets[textDirection];
+        var p3 = {
+          height,
+          width: width2,
+          x: coord3[0] + offset[0],
+          y: coord3[1] + offset[1],
+          textAnchor: offset[2]
+        };
+        var bbox3;
+        if (textDirection === "rtl") {
+          bbox3 = {
+            minX: p3.x - width2 - textPadding,
+            minY: p3.y - height / 2 - textPadding,
+            maxX: p3.x + textPadding,
+            maxY: p3.y + height / 2 + textPadding
+          };
+        } else {
+          bbox3 = {
+            minX: p3.x - textPadding,
+            minY: p3.y - height / 2 - textPadding,
+            maxX: p3.x + width2 + textPadding,
+            maxY: p3.y + height / 2 + textPadding
+          };
+        }
+        if (tryInsert([bbox3], entity2.id, true)) {
+          return p3;
+        }
       }
-      context.container().select(".main-footer-wrap").classed("footer-hide", true).classed("footer-show", false);
-      context.container().select(".flash-wrap").classed("footer-hide", false).classed("footer-show", true);
-      var content = context.container().select(".flash-wrap").selectAll(".flash-content").data([0]);
-      var contentEnter = content.enter().append("div").attr("class", "flash-content");
-      var iconEnter = contentEnter.append("svg").attr("class", "flash-icon icon").append("g").attr("transform", "translate(10,10)");
-      iconEnter.append("circle").attr("r", 9);
-      iconEnter.append("use").attr("transform", "translate(-7,-7)").attr("width", "14").attr("height", "14");
-      contentEnter.append("div").attr("class", "flash-text");
-      content = content.merge(contentEnter);
-      content.selectAll(".flash-icon").attr("class", "icon flash-icon " + (_iconClass || ""));
-      content.selectAll(".flash-icon use").attr("xlink:href", _iconName);
-      content.selectAll(".flash-text").attr("class", "flash-text").call(_label);
-      _flashTimer = timeout_default(function() {
-        _flashTimer = null;
-        context.container().select(".main-footer-wrap").classed("footer-hide", false).classed("footer-show", true);
-        context.container().select(".flash-wrap").classed("footer-hide", true).classed("footer-show", false);
-      }, _duration);
-      return content;
+      function getLineLabel(entity2, width2, height) {
+        var viewport = geoExtent(context.projection.clipExtent()).polygon();
+        var points = graph.childNodes(entity2).map(function(node) {
+          return projection2(node.loc);
+        });
+        var length2 = geoPathLength(points);
+        if (length2 < width2 + 20) return;
+        var lineOffsets = [
+          50,
+          45,
+          55,
+          40,
+          60,
+          35,
+          65,
+          30,
+          70,
+          25,
+          75,
+          20,
+          80,
+          15,
+          95,
+          10,
+          90,
+          5,
+          95
+        ];
+        var padding = 3;
+        for (var i4 = 0; i4 < lineOffsets.length; i4++) {
+          var offset = lineOffsets[i4];
+          var middle = offset / 100 * length2;
+          var start2 = middle - width2 / 2;
+          if (start2 < 0 || start2 + width2 > length2) continue;
+          var sub = subpath(points, start2, start2 + width2);
+          if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
+            continue;
+          }
+          var isReverse = reverse(sub);
+          if (isReverse) {
+            sub = sub.reverse();
+          }
+          var bboxes = [];
+          var boxsize = (height + 2) / 2;
+          for (var j3 = 0; j3 < sub.length - 1; j3++) {
+            var a2 = sub[j3];
+            var b2 = sub[j3 + 1];
+            var num = Math.max(1, Math.floor(geoVecLength(a2, b2) / boxsize / 2));
+            for (var box = 0; box < num; box++) {
+              var p3 = geoVecInterp(a2, b2, box / num);
+              var x05 = p3[0] - boxsize - padding;
+              var y05 = p3[1] - boxsize - padding;
+              var x12 = p3[0] + boxsize + padding;
+              var y12 = p3[1] + boxsize + padding;
+              bboxes.push({
+                minX: Math.min(x05, x12),
+                minY: Math.min(y05, y12),
+                maxX: Math.max(x05, x12),
+                maxY: Math.max(y05, y12)
+              });
+            }
+          }
+          if (tryInsert(bboxes, entity2.id, false)) {
+            return {
+              "font-size": height + 2,
+              lineString: lineString2(sub),
+              startOffset: offset + "%"
+            };
+          }
+        }
+        function reverse(p4) {
+          var angle2 = Math.atan2(p4[1][1] - p4[0][1], p4[1][0] - p4[0][0]);
+          return !(p4[0][0] < p4[p4.length - 1][0] && angle2 < Math.PI / 2 && angle2 > -Math.PI / 2);
+        }
+        function lineString2(points2) {
+          return "M" + points2.join("L");
+        }
+        function subpath(points2, from, to) {
+          var sofar = 0;
+          var start3, end, i0, i1;
+          for (var i5 = 0; i5 < points2.length - 1; i5++) {
+            var a3 = points2[i5];
+            var b3 = points2[i5 + 1];
+            var current = geoVecLength(a3, b3);
+            var portion;
+            if (!start3 && sofar + current >= from) {
+              portion = (from - sofar) / current;
+              start3 = [
+                a3[0] + portion * (b3[0] - a3[0]),
+                a3[1] + portion * (b3[1] - a3[1])
+              ];
+              i0 = i5 + 1;
+            }
+            if (!end && sofar + current >= to) {
+              portion = (to - sofar) / current;
+              end = [
+                a3[0] + portion * (b3[0] - a3[0]),
+                a3[1] + portion * (b3[1] - a3[1])
+              ];
+              i1 = i5 + 1;
+            }
+            sofar += current;
+          }
+          var result = points2.slice(i0, i1);
+          result.unshift(start3);
+          result.push(end);
+          return result;
+        }
+      }
+      function getAreaLabel(entity2, width2, height) {
+        var centroid = path.centroid(entity2.asGeoJSON(graph));
+        var extent = entity2.extent(graph);
+        var areaWidth = projection2(extent[1])[0] - projection2(extent[0])[0];
+        if (isNaN(centroid[0]) || areaWidth < 20) return;
+        var preset2 = _mainPresetIndex.match(entity2, context.graph());
+        var picon = preset2 && preset2.icon;
+        var iconSize = 17;
+        var padding = 2;
+        var p3 = {};
+        if (picon) {
+          if (addIcon()) {
+            addLabel(iconSize + padding);
+            return p3;
+          }
+        } else {
+          if (addLabel(0)) {
+            return p3;
+          }
+        }
+        function addIcon() {
+          var iconX = centroid[0] - iconSize / 2;
+          var iconY = centroid[1] - iconSize / 2;
+          var bbox3 = {
+            minX: iconX,
+            minY: iconY,
+            maxX: iconX + iconSize,
+            maxY: iconY + iconSize
+          };
+          if (tryInsert([bbox3], entity2.id + "I", true)) {
+            p3.transform = "translate(" + iconX + "," + iconY + ")";
+            return true;
+          }
+          return false;
+        }
+        function addLabel(yOffset) {
+          if (width2 && areaWidth >= width2 + 20) {
+            var labelX = centroid[0];
+            var labelY = centroid[1] + yOffset;
+            var bbox3 = {
+              minX: labelX - width2 / 2 - padding,
+              minY: labelY - height / 2 - padding,
+              maxX: labelX + width2 / 2 + padding,
+              maxY: labelY + height / 2 + padding
+            };
+            if (tryInsert([bbox3], entity2.id, true)) {
+              p3.x = labelX;
+              p3.y = labelY;
+              p3.textAnchor = "middle";
+              p3.height = height;
+              return true;
+            }
+          }
+          return false;
+        }
+      }
+      function doInsert(bbox3, id2) {
+        bbox3.id = id2;
+        var oldbox = _entitybboxes[id2];
+        if (oldbox) {
+          _rdrawn.remove(oldbox);
+        }
+        _entitybboxes[id2] = bbox3;
+        _rdrawn.insert(bbox3);
+      }
+      function tryInsert(bboxes, id2, saveSkipped) {
+        var skipped = false;
+        for (var i4 = 0; i4 < bboxes.length; i4++) {
+          var bbox3 = bboxes[i4];
+          bbox3.id = id2;
+          if (bbox3.minX < 0 || bbox3.minY < 0 || bbox3.maxX > dimensions[0] || bbox3.maxY > dimensions[1]) {
+            skipped = true;
+            break;
+          }
+          if (_rdrawn.collides(bbox3)) {
+            skipped = true;
+            break;
+          }
+        }
+        _entitybboxes[id2] = bboxes;
+        if (skipped) {
+          if (saveSkipped) {
+            _rskipped.load(bboxes);
+          }
+        } else {
+          _rdrawn.load(bboxes);
+        }
+        return !skipped;
+      }
+      var layer = selection2.selectAll(".layer-osm.labels");
+      layer.selectAll(".labels-group").data(["halo", "label", "debug"]).enter().append("g").attr("class", function(d2) {
+        return "labels-group " + d2;
+      });
+      var halo = layer.selectAll(".labels-group.halo");
+      var label = layer.selectAll(".labels-group.label");
+      var debug2 = layer.selectAll(".labels-group.debug");
+      drawPointLabels(label, labelled.point, filter2, "pointlabel", positions.point);
+      drawPointLabels(halo, labelled.point, filter2, "pointlabel-halo", positions.point);
+      drawLinePaths(layer, labelled.line, filter2, "", positions.line);
+      drawLineLabels(label, labelled.line, filter2, "linelabel", positions.line);
+      drawLineLabels(halo, labelled.line, filter2, "linelabel-halo", positions.line);
+      drawAreaLabels(label, labelled.area, filter2, "arealabel", positions.area);
+      drawAreaLabels(halo, labelled.area, filter2, "arealabel-halo", positions.area);
+      drawAreaIcons(label, labelled.area, filter2, "areaicon", positions.area);
+      drawAreaIcons(halo, labelled.area, filter2, "areaicon-halo", positions.area);
+      drawCollisionBoxes(debug2, _rskipped, "debug-skipped");
+      drawCollisionBoxes(debug2, _rdrawn, "debug-drawn");
+      layer.call(filterLabels);
     }
-    flash.duration = function(_) {
-      if (!arguments.length)
-        return _duration;
-      _duration = _;
-      return flash;
-    };
-    flash.label = function(_) {
-      if (!arguments.length)
-        return _label;
-      if (typeof _ !== "function") {
-        _label = (selection2) => selection2.text(_);
-      } else {
-        _label = (selection2) => selection2.text("").call(_);
+    function filterLabels(selection2) {
+      var drawLayer = selection2.selectAll(".layer-osm.labels");
+      var layers = drawLayer.selectAll(".labels-group.halo, .labels-group.label");
+      layers.selectAll(".nolabel").classed("nolabel", false);
+      var mouse = context.map().mouse();
+      var graph = context.graph();
+      var selectedIDs = context.selectedIDs();
+      var ids = [];
+      var pad2, bbox2;
+      if (mouse) {
+        pad2 = 20;
+        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);
       }
-      return flash;
-    };
-    flash.iconName = function(_) {
-      if (!arguments.length)
-        return _iconName;
-      _iconName = _;
-      return flash;
+      for (var i3 = 0; i3 < selectedIDs.length; i3++) {
+        var entity = graph.hasEntity(selectedIDs[i3]);
+        if (entity && entity.type === "node") {
+          ids.push(selectedIDs[i3]);
+        }
+      }
+      layers.selectAll(utilEntitySelector(ids)).classed("nolabel", true);
+      var debug2 = selection2.selectAll(".labels-group.debug");
+      var gj = [];
+      if (context.getDebug("collision")) {
+        gj = bbox2 ? [{
+          type: "Polygon",
+          coordinates: [[
+            [bbox2.minX, bbox2.minY],
+            [bbox2.maxX, bbox2.minY],
+            [bbox2.maxX, bbox2.maxY],
+            [bbox2.minX, bbox2.maxY],
+            [bbox2.minX, bbox2.minY]
+          ]]
+        }] : [];
+      }
+      var box = debug2.selectAll(".debug-mouse").data(gj);
+      box.exit().remove();
+      box.enter().append("path").attr("class", "debug debug-mouse yellow").merge(box).attr("d", path_default());
+    }
+    var throttleFilterLabels = throttle_default(filterLabels, 100);
+    drawLabels.observe = function(selection2) {
+      var listener = function() {
+        throttleFilterLabels(selection2);
+      };
+      selection2.on("mousemove.hidelabels", listener);
+      context.on("enter.hidelabels", listener);
     };
-    flash.iconClass = function(_) {
-      if (!arguments.length)
-        return _iconClass;
-      _iconClass = _;
-      return flash;
+    drawLabels.off = function(selection2) {
+      throttleFilterLabels.cancel();
+      selection2.on("mousemove.hidelabels", null);
+      context.on("enter.hidelabels", null);
     };
-    return flash;
+    return drawLabels;
   }
 
-  // modules/ui/full_screen.js
-  function uiFullScreen(context) {
-    var element = context.container().node();
-    function getFullScreenFn() {
-      if (element.requestFullscreen) {
-        return element.requestFullscreen;
-      } else if (element.msRequestFullscreen) {
-        return element.msRequestFullscreen;
-      } else if (element.mozRequestFullScreen) {
-        return element.mozRequestFullScreen;
-      } else if (element.webkitRequestFullscreen) {
-        return element.webkitRequestFullscreen;
+  // node_modules/exifr/dist/full.esm.mjs
+  var e = "undefined" != typeof self ? self : global;
+  var t = "undefined" != typeof navigator;
+  var i2 = t && "undefined" == typeof HTMLImageElement;
+  var n2 = !("undefined" == typeof global || "undefined" == typeof process || !process.versions || !process.versions.node);
+  var s = e.Buffer;
+  var r = e.BigInt;
+  var a = !!s;
+  var o = (e3) => e3;
+  function l(e3, t2 = o) {
+    if (n2) try {
+      return "function" == typeof __require ? Promise.resolve(t2(__require(e3))) : import(
+        /* webpackIgnore: true */
+        e3
+      ).then(t2);
+    } catch (t3) {
+      console.warn("Couldn't load ".concat(e3));
+    }
+  }
+  var h = e.fetch;
+  var u = (e3) => h = e3;
+  if (!e.fetch) {
+    const e3 = l("http", (e4) => e4), t2 = l("https", (e4) => e4), i3 = (n3, { headers: s2 } = {}) => new Promise(async (r2, a2) => {
+      let { port: o2, hostname: l2, pathname: h2, protocol: u2, search: c2 } = new URL(n3);
+      const f2 = { method: "GET", hostname: l2, path: encodeURI(h2) + c2, headers: s2 };
+      "" !== o2 && (f2.port = Number(o2));
+      const d2 = ("https:" === u2 ? await t2 : await e3).request(f2, (e4) => {
+        if (301 === e4.statusCode || 302 === e4.statusCode) {
+          let t3 = new URL(e4.headers.location, n3).toString();
+          return i3(t3, { headers: s2 }).then(r2).catch(a2);
+        }
+        r2({ status: e4.statusCode, arrayBuffer: () => new Promise((t3) => {
+          let i4 = [];
+          e4.on("data", (e6) => i4.push(e6)), e4.on("end", () => t3(Buffer.concat(i4)));
+        }) });
+      });
+      d2.on("error", a2), d2.end();
+    });
+    u(i3);
+  }
+  function c(e3, t2, i3) {
+    return t2 in e3 ? Object.defineProperty(e3, t2, { value: i3, enumerable: true, configurable: true, writable: true }) : e3[t2] = i3, e3;
+  }
+  var f = (e3) => p(e3) ? void 0 : e3;
+  var d = (e3) => void 0 !== e3;
+  function p(e3) {
+    return void 0 === e3 || (e3 instanceof Map ? 0 === e3.size : 0 === Object.values(e3).filter(d).length);
+  }
+  function g2(e3) {
+    let t2 = new Error(e3);
+    throw delete t2.stack, t2;
+  }
+  function m(e3) {
+    return "" === (e3 = function(e4) {
+      for (; e4.endsWith("\0"); ) e4 = e4.slice(0, -1);
+      return e4;
+    }(e3).trim()) ? void 0 : e3;
+  }
+  function S(e3) {
+    let t2 = function(e4) {
+      let t3 = 0;
+      return e4.ifd0.enabled && (t3 += 1024), e4.exif.enabled && (t3 += 2048), e4.makerNote && (t3 += 2048), e4.userComment && (t3 += 1024), e4.gps.enabled && (t3 += 512), e4.interop.enabled && (t3 += 100), e4.ifd1.enabled && (t3 += 1024), t3 + 2048;
+    }(e3);
+    return e3.jfif.enabled && (t2 += 50), e3.xmp.enabled && (t2 += 2e4), e3.iptc.enabled && (t2 += 14e3), e3.icc.enabled && (t2 += 6e3), t2;
+  }
+  var C = (e3) => String.fromCharCode.apply(null, e3);
+  var y = "undefined" != typeof TextDecoder ? new TextDecoder("utf-8") : void 0;
+  function b(e3) {
+    return y ? y.decode(e3) : a ? Buffer.from(e3).toString("utf8") : decodeURIComponent(escape(C(e3)));
+  }
+  var I = class _I {
+    static from(e3, t2) {
+      return e3 instanceof this && e3.le === t2 ? e3 : new _I(e3, void 0, void 0, t2);
+    }
+    constructor(e3, t2 = 0, i3, n3) {
+      if ("boolean" == typeof n3 && (this.le = n3), Array.isArray(e3) && (e3 = new Uint8Array(e3)), 0 === e3) this.byteOffset = 0, this.byteLength = 0;
+      else if (e3 instanceof ArrayBuffer) {
+        void 0 === i3 && (i3 = e3.byteLength - t2);
+        let n4 = new DataView(e3, t2, i3);
+        this._swapDataView(n4);
+      } else if (e3 instanceof Uint8Array || e3 instanceof DataView || e3 instanceof _I) {
+        void 0 === i3 && (i3 = e3.byteLength - t2), (t2 += e3.byteOffset) + i3 > e3.byteOffset + e3.byteLength && g2("Creating view outside of available memory in ArrayBuffer");
+        let n4 = new DataView(e3.buffer, t2, i3);
+        this._swapDataView(n4);
+      } else if ("number" == typeof e3) {
+        let t3 = new DataView(new ArrayBuffer(e3));
+        this._swapDataView(t3);
+      } else g2("Invalid input argument for BufferView: " + e3);
+    }
+    _swapArrayBuffer(e3) {
+      this._swapDataView(new DataView(e3));
+    }
+    _swapBuffer(e3) {
+      this._swapDataView(new DataView(e3.buffer, e3.byteOffset, e3.byteLength));
+    }
+    _swapDataView(e3) {
+      this.dataView = e3, this.buffer = e3.buffer, this.byteOffset = e3.byteOffset, this.byteLength = e3.byteLength;
+    }
+    _lengthToEnd(e3) {
+      return this.byteLength - e3;
+    }
+    set(e3, t2, i3 = _I) {
+      return e3 instanceof DataView || e3 instanceof _I ? e3 = new Uint8Array(e3.buffer, e3.byteOffset, e3.byteLength) : e3 instanceof ArrayBuffer && (e3 = new Uint8Array(e3)), e3 instanceof Uint8Array || g2("BufferView.set(): Invalid data argument."), this.toUint8().set(e3, t2), new i3(this, t2, e3.byteLength);
+    }
+    subarray(e3, t2) {
+      return t2 = t2 || this._lengthToEnd(e3), new _I(this, e3, t2);
+    }
+    toUint8() {
+      return new Uint8Array(this.buffer, this.byteOffset, this.byteLength);
+    }
+    getUint8Array(e3, t2) {
+      return new Uint8Array(this.buffer, this.byteOffset + e3, t2);
+    }
+    getString(e3 = 0, t2 = this.byteLength) {
+      return b(this.getUint8Array(e3, t2));
+    }
+    getLatin1String(e3 = 0, t2 = this.byteLength) {
+      let i3 = this.getUint8Array(e3, t2);
+      return C(i3);
+    }
+    getUnicodeString(e3 = 0, t2 = this.byteLength) {
+      const i3 = [];
+      for (let n3 = 0; n3 < t2 && e3 + n3 < this.byteLength; n3 += 2) i3.push(this.getUint16(e3 + n3));
+      return C(i3);
+    }
+    getInt8(e3) {
+      return this.dataView.getInt8(e3);
+    }
+    getUint8(e3) {
+      return this.dataView.getUint8(e3);
+    }
+    getInt16(e3, t2 = this.le) {
+      return this.dataView.getInt16(e3, t2);
+    }
+    getInt32(e3, t2 = this.le) {
+      return this.dataView.getInt32(e3, t2);
+    }
+    getUint16(e3, t2 = this.le) {
+      return this.dataView.getUint16(e3, t2);
+    }
+    getUint32(e3, t2 = this.le) {
+      return this.dataView.getUint32(e3, t2);
+    }
+    getFloat32(e3, t2 = this.le) {
+      return this.dataView.getFloat32(e3, t2);
+    }
+    getFloat64(e3, t2 = this.le) {
+      return this.dataView.getFloat64(e3, t2);
+    }
+    getFloat(e3, t2 = this.le) {
+      return this.dataView.getFloat32(e3, t2);
+    }
+    getDouble(e3, t2 = this.le) {
+      return this.dataView.getFloat64(e3, t2);
+    }
+    getUintBytes(e3, t2, i3) {
+      switch (t2) {
+        case 1:
+          return this.getUint8(e3, i3);
+        case 2:
+          return this.getUint16(e3, i3);
+        case 4:
+          return this.getUint32(e3, i3);
+        case 8:
+          return this.getUint64 && this.getUint64(e3, i3);
       }
     }
-    function getExitFullScreenFn() {
-      if (document.exitFullscreen) {
-        return document.exitFullscreen;
-      } else if (document.msExitFullscreen) {
-        return document.msExitFullscreen;
-      } else if (document.mozCancelFullScreen) {
-        return document.mozCancelFullScreen;
-      } else if (document.webkitExitFullscreen) {
-        return document.webkitExitFullscreen;
+    getUint(e3, t2, i3) {
+      switch (t2) {
+        case 8:
+          return this.getUint8(e3, i3);
+        case 16:
+          return this.getUint16(e3, i3);
+        case 32:
+          return this.getUint32(e3, i3);
+        case 64:
+          return this.getUint64 && this.getUint64(e3, i3);
       }
     }
-    function isFullScreen() {
-      return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
+    toString(e3) {
+      return this.dataView.toString(e3, this.constructor.name);
     }
-    function isSupported() {
-      return !!getFullScreenFn();
+    ensureChunk() {
     }
-    function fullScreen(d3_event) {
-      d3_event.preventDefault();
-      if (!isFullScreen()) {
-        getFullScreenFn().apply(element);
-      } else {
-        getExitFullScreenFn().apply(document);
-      }
+  };
+  function P(e3, t2) {
+    g2("".concat(e3, " '").concat(t2, "' was not loaded, try using full build of exifr."));
+  }
+  var k = class extends Map {
+    constructor(e3) {
+      super(), this.kind = e3;
     }
-    return function() {
-      if (!isSupported())
-        return;
-      var detected = utilDetect();
-      var keys = detected.os === "mac" ? [uiCmd("\u2303\u2318F"), "f11"] : ["f11"];
-      context.keybinding().on(keys, fullScreen);
-    };
+    get(e3, t2) {
+      return this.has(e3) || P(this.kind, e3), t2 && (e3 in t2 || function(e4, t3) {
+        g2("Unknown ".concat(e4, " '").concat(t3, "'."));
+      }(this.kind, e3), t2[e3].enabled || P(this.kind, e3)), super.get(e3);
+    }
+    keyList() {
+      return Array.from(this.keys());
+    }
+  };
+  var w = new k("file parser");
+  var T = new k("segment parser");
+  var A = new k("file reader");
+  function D(e3, n3) {
+    return "string" == typeof e3 ? O(e3, n3) : t && !i2 && e3 instanceof HTMLImageElement ? O(e3.src, n3) : e3 instanceof Uint8Array || e3 instanceof ArrayBuffer || e3 instanceof DataView ? new I(e3) : t && e3 instanceof Blob ? x(e3, n3, "blob", R) : void g2("Invalid input argument");
+  }
+  function O(e3, i3) {
+    return (s2 = e3).startsWith("data:") || s2.length > 1e4 ? v(e3, i3, "base64") : n2 && e3.includes("://") ? x(e3, i3, "url", M) : n2 ? v(e3, i3, "fs") : t ? x(e3, i3, "url", M) : void g2("Invalid input argument");
+    var s2;
+  }
+  async function x(e3, t2, i3, n3) {
+    return A.has(i3) ? v(e3, t2, i3) : n3 ? async function(e4, t3) {
+      let i4 = await t3(e4);
+      return new I(i4);
+    }(e3, n3) : void g2("Parser ".concat(i3, " is not loaded"));
+  }
+  async function v(e3, t2, i3) {
+    let n3 = new (A.get(i3))(e3, t2);
+    return await n3.read(), n3;
+  }
+  var M = (e3) => h(e3).then((e4) => e4.arrayBuffer());
+  var R = (e3) => new Promise((t2, i3) => {
+    let n3 = new FileReader();
+    n3.onloadend = () => t2(n3.result || new ArrayBuffer()), n3.onerror = i3, n3.readAsArrayBuffer(e3);
+  });
+  var L = class extends Map {
+    get tagKeys() {
+      return this.allKeys || (this.allKeys = Array.from(this.keys())), this.allKeys;
+    }
+    get tagValues() {
+      return this.allValues || (this.allValues = Array.from(this.values())), this.allValues;
+    }
+  };
+  function U(e3, t2, i3) {
+    let n3 = new L();
+    for (let [e4, t3] of i3) n3.set(e4, t3);
+    if (Array.isArray(t2)) for (let i4 of t2) e3.set(i4, n3);
+    else e3.set(t2, n3);
+    return n3;
+  }
+  function F(e3, t2, i3) {
+    let n3, s2 = e3.get(t2);
+    for (n3 of i3) s2.set(n3[0], n3[1]);
+  }
+  var E = /* @__PURE__ */ new Map();
+  var B = /* @__PURE__ */ new Map();
+  var N = /* @__PURE__ */ new Map();
+  var G = ["chunked", "firstChunkSize", "firstChunkSizeNode", "firstChunkSizeBrowser", "chunkSize", "chunkLimit"];
+  var V = ["jfif", "xmp", "icc", "iptc", "ihdr"];
+  var z = ["tiff", ...V];
+  var H = ["ifd0", "ifd1", "exif", "gps", "interop"];
+  var j = [...z, ...H];
+  var W = ["makerNote", "userComment"];
+  var K = ["translateKeys", "translateValues", "reviveValues", "multiSegment"];
+  var X = [...K, "sanitize", "mergeOutput", "silentErrors"];
+  var _ = class {
+    get translate() {
+      return this.translateKeys || this.translateValues || this.reviveValues;
+    }
+  };
+  var Y = class extends _ {
+    get needed() {
+      return this.enabled || this.deps.size > 0;
+    }
+    constructor(e3, t2, i3, n3) {
+      if (super(), c(this, "enabled", false), c(this, "skip", /* @__PURE__ */ new Set()), c(this, "pick", /* @__PURE__ */ new Set()), c(this, "deps", /* @__PURE__ */ new Set()), c(this, "translateKeys", false), c(this, "translateValues", false), c(this, "reviveValues", false), this.key = e3, this.enabled = t2, this.parse = this.enabled, this.applyInheritables(n3), this.canBeFiltered = H.includes(e3), this.canBeFiltered && (this.dict = E.get(e3)), void 0 !== i3) if (Array.isArray(i3)) this.parse = this.enabled = true, this.canBeFiltered && i3.length > 0 && this.translateTagSet(i3, this.pick);
+      else if ("object" == typeof i3) {
+        if (this.enabled = true, this.parse = false !== i3.parse, this.canBeFiltered) {
+          let { pick: e4, skip: t3 } = i3;
+          e4 && e4.length > 0 && this.translateTagSet(e4, this.pick), t3 && t3.length > 0 && this.translateTagSet(t3, this.skip);
+        }
+        this.applyInheritables(i3);
+      } else true === i3 || false === i3 ? this.parse = this.enabled = i3 : g2("Invalid options argument: ".concat(i3));
+    }
+    applyInheritables(e3) {
+      let t2, i3;
+      for (t2 of K) i3 = e3[t2], void 0 !== i3 && (this[t2] = i3);
+    }
+    translateTagSet(e3, t2) {
+      if (this.dict) {
+        let i3, n3, { tagKeys: s2, tagValues: r2 } = this.dict;
+        for (i3 of e3) "string" == typeof i3 ? (n3 = r2.indexOf(i3), -1 === n3 && (n3 = s2.indexOf(Number(i3))), -1 !== n3 && t2.add(Number(s2[n3]))) : t2.add(i3);
+      } else for (let i3 of e3) t2.add(i3);
+    }
+    finalizeFilters() {
+      !this.enabled && this.deps.size > 0 ? (this.enabled = true, ee(this.pick, this.deps)) : this.enabled && this.pick.size > 0 && ee(this.pick, this.deps);
+    }
+  };
+  var $2 = { jfif: false, tiff: true, xmp: false, icc: false, iptc: false, ifd0: true, ifd1: false, exif: true, gps: true, interop: false, ihdr: void 0, makerNote: false, userComment: false, multiSegment: false, skip: [], pick: [], translateKeys: true, translateValues: true, reviveValues: true, sanitize: true, mergeOutput: true, silentErrors: true, chunked: true, firstChunkSize: void 0, firstChunkSizeNode: 512, firstChunkSizeBrowser: 65536, chunkSize: 65536, chunkLimit: 5 };
+  var J = /* @__PURE__ */ new Map();
+  var q = class extends _ {
+    static useCached(e3) {
+      let t2 = J.get(e3);
+      return void 0 !== t2 || (t2 = new this(e3), J.set(e3, t2)), t2;
+    }
+    constructor(e3) {
+      super(), true === e3 ? this.setupFromTrue() : void 0 === e3 ? this.setupFromUndefined() : Array.isArray(e3) ? this.setupFromArray(e3) : "object" == typeof e3 ? this.setupFromObject(e3) : g2("Invalid options argument ".concat(e3)), void 0 === this.firstChunkSize && (this.firstChunkSize = t ? this.firstChunkSizeBrowser : this.firstChunkSizeNode), this.mergeOutput && (this.ifd1.enabled = false), this.filterNestedSegmentTags(), this.traverseTiffDependencyTree(), this.checkLoadedPlugins();
+    }
+    setupFromUndefined() {
+      let e3;
+      for (e3 of G) this[e3] = $2[e3];
+      for (e3 of X) this[e3] = $2[e3];
+      for (e3 of W) this[e3] = $2[e3];
+      for (e3 of j) this[e3] = new Y(e3, $2[e3], void 0, this);
+    }
+    setupFromTrue() {
+      let e3;
+      for (e3 of G) this[e3] = $2[e3];
+      for (e3 of X) this[e3] = $2[e3];
+      for (e3 of W) this[e3] = true;
+      for (e3 of j) this[e3] = new Y(e3, true, void 0, this);
+    }
+    setupFromArray(e3) {
+      let t2;
+      for (t2 of G) this[t2] = $2[t2];
+      for (t2 of X) this[t2] = $2[t2];
+      for (t2 of W) this[t2] = $2[t2];
+      for (t2 of j) this[t2] = new Y(t2, false, void 0, this);
+      this.setupGlobalFilters(e3, void 0, H);
+    }
+    setupFromObject(e3) {
+      let t2;
+      for (t2 of (H.ifd0 = H.ifd0 || H.image, H.ifd1 = H.ifd1 || H.thumbnail, Object.assign(this, e3), G)) this[t2] = Z(e3[t2], $2[t2]);
+      for (t2 of X) this[t2] = Z(e3[t2], $2[t2]);
+      for (t2 of W) this[t2] = Z(e3[t2], $2[t2]);
+      for (t2 of z) this[t2] = new Y(t2, $2[t2], e3[t2], this);
+      for (t2 of H) this[t2] = new Y(t2, $2[t2], e3[t2], this.tiff);
+      this.setupGlobalFilters(e3.pick, e3.skip, H, j), true === e3.tiff ? this.batchEnableWithBool(H, true) : false === e3.tiff ? this.batchEnableWithUserValue(H, e3) : Array.isArray(e3.tiff) ? this.setupGlobalFilters(e3.tiff, void 0, H) : "object" == typeof e3.tiff && this.setupGlobalFilters(e3.tiff.pick, e3.tiff.skip, H);
+    }
+    batchEnableWithBool(e3, t2) {
+      for (let i3 of e3) this[i3].enabled = t2;
+    }
+    batchEnableWithUserValue(e3, t2) {
+      for (let i3 of e3) {
+        let e4 = t2[i3];
+        this[i3].enabled = false !== e4 && void 0 !== e4;
+      }
+    }
+    setupGlobalFilters(e3, t2, i3, n3 = i3) {
+      if (e3 && e3.length) {
+        for (let e4 of n3) this[e4].enabled = false;
+        let t3 = Q(e3, i3);
+        for (let [e4, i4] of t3) ee(this[e4].pick, i4), this[e4].enabled = true;
+      } else if (t2 && t2.length) {
+        let e4 = Q(t2, i3);
+        for (let [t3, i4] of e4) ee(this[t3].skip, i4);
+      }
+    }
+    filterNestedSegmentTags() {
+      let { ifd0: e3, exif: t2, xmp: i3, iptc: n3, icc: s2 } = this;
+      this.makerNote ? t2.deps.add(37500) : t2.skip.add(37500), this.userComment ? t2.deps.add(37510) : t2.skip.add(37510), i3.enabled || e3.skip.add(700), n3.enabled || e3.skip.add(33723), s2.enabled || e3.skip.add(34675);
+    }
+    traverseTiffDependencyTree() {
+      let { ifd0: e3, exif: t2, gps: i3, interop: n3 } = this;
+      n3.needed && (t2.deps.add(40965), e3.deps.add(40965)), t2.needed && e3.deps.add(34665), i3.needed && e3.deps.add(34853), this.tiff.enabled = H.some((e4) => true === this[e4].enabled) || this.makerNote || this.userComment;
+      for (let e4 of H) this[e4].finalizeFilters();
+    }
+    get onlyTiff() {
+      return !V.map((e3) => this[e3].enabled).some((e3) => true === e3) && this.tiff.enabled;
+    }
+    checkLoadedPlugins() {
+      for (let e3 of z) this[e3].enabled && !T.has(e3) && P("segment parser", e3);
+    }
+  };
+  function Q(e3, t2) {
+    let i3, n3, s2, r2, a2 = [];
+    for (s2 of t2) {
+      for (r2 of (i3 = E.get(s2), n3 = [], i3)) (e3.includes(r2[0]) || e3.includes(r2[1])) && n3.push(r2[0]);
+      n3.length && a2.push([s2, n3]);
+    }
+    return a2;
+  }
+  function Z(e3, t2) {
+    return void 0 !== e3 ? e3 : void 0 !== t2 ? t2 : void 0;
+  }
+  function ee(e3, t2) {
+    for (let i3 of t2) e3.add(i3);
+  }
+  c(q, "default", $2);
+  var te = class {
+    constructor(e3) {
+      c(this, "parsers", {}), c(this, "output", {}), c(this, "errors", []), c(this, "pushToErrors", (e4) => this.errors.push(e4)), this.options = q.useCached(e3);
+    }
+    async read(e3) {
+      this.file = await D(e3, this.options);
+    }
+    setup() {
+      if (this.fileParser) return;
+      let { file: e3 } = this, t2 = e3.getUint16(0);
+      for (let [i3, n3] of w) if (n3.canHandle(e3, t2)) return this.fileParser = new n3(this.options, this.file, this.parsers), e3[i3] = true;
+      this.file.close && this.file.close(), g2("Unknown file format");
+    }
+    async parse() {
+      let { output: e3, errors: t2 } = this;
+      return this.setup(), this.options.silentErrors ? (await this.executeParsers().catch(this.pushToErrors), t2.push(...this.fileParser.errors)) : await this.executeParsers(), this.file.close && this.file.close(), this.options.silentErrors && t2.length > 0 && (e3.errors = t2), f(e3);
+    }
+    async executeParsers() {
+      let { output: e3 } = this;
+      await this.fileParser.parse();
+      let t2 = Object.values(this.parsers).map(async (t3) => {
+        let i3 = await t3.parse();
+        t3.assignToOutput(e3, i3);
+      });
+      this.options.silentErrors && (t2 = t2.map((e4) => e4.catch(this.pushToErrors))), await Promise.all(t2);
+    }
+    async extractThumbnail() {
+      this.setup();
+      let { options: e3, file: t2 } = this, i3 = T.get("tiff", e3);
+      var n3;
+      if (t2.tiff ? n3 = { start: 0, type: "tiff" } : t2.jpeg && (n3 = await this.fileParser.getOrFindSegment("tiff")), void 0 === n3) return;
+      let s2 = await this.fileParser.ensureSegmentChunk(n3), r2 = this.parsers.tiff = new i3(s2, e3, t2), a2 = await r2.extractThumbnail();
+      return t2.close && t2.close(), a2;
+    }
+  };
+  async function ie(e3, t2) {
+    let i3 = new te(t2);
+    return await i3.read(e3), i3.parse();
   }
-
-  // modules/ui/geolocate.js
-  function uiGeolocate(context) {
-    var _geolocationOptions = {
-      enableHighAccuracy: false,
-      timeout: 6e3
-    };
-    var _locating = uiLoading(context).message(_t.html("geolocate.locating")).blocking(true);
-    var _layer = context.layers().layer("geolocate");
-    var _position;
-    var _extent;
-    var _timeoutID;
-    var _button = select_default2(null);
-    function click() {
-      if (context.inIntro())
-        return;
-      if (!_layer.enabled() && !_locating.isShown()) {
-        _timeoutID = setTimeout(error, 1e4);
-        context.container().call(_locating);
-        navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
-      } else {
-        _locating.close();
-        _layer.enabled(null, false);
-        updateButtonState();
-      }
+  var ne = Object.freeze({ __proto__: null, parse: ie, Exifr: te, fileParsers: w, segmentParsers: T, fileReaders: A, tagKeys: E, tagValues: B, tagRevivers: N, createDictionary: U, extendDictionary: F, fetchUrlAsArrayBuffer: M, readBlobAsArrayBuffer: R, chunkedProps: G, otherSegments: V, segments: z, tiffBlocks: H, segmentsAndBlocks: j, tiffExtractables: W, inheritables: K, allFormatters: X, Options: q });
+  var se = class {
+    constructor(e3, t2, i3) {
+      c(this, "errors", []), c(this, "ensureSegmentChunk", async (e4) => {
+        let t3 = e4.start, i4 = e4.size || 65536;
+        if (this.file.chunked) if (this.file.available(t3, i4)) e4.chunk = this.file.subarray(t3, i4);
+        else try {
+          e4.chunk = await this.file.readChunk(t3, i4);
+        } catch (t4) {
+          g2("Couldn't read segment: ".concat(JSON.stringify(e4), ". ").concat(t4.message));
+        }
+        else this.file.byteLength > t3 + i4 ? e4.chunk = this.file.subarray(t3, i4) : void 0 === e4.size ? e4.chunk = this.file.subarray(t3) : g2("Segment unreachable: " + JSON.stringify(e4));
+        return e4.chunk;
+      }), this.extendOptions && this.extendOptions(e3), this.options = e3, this.file = t2, this.parsers = i3;
     }
-    function zoomTo() {
-      context.enter(modeBrowse(context));
-      var map2 = context.map();
-      _layer.enabled(_position, true);
-      updateButtonState();
-      map2.centerZoomEase(_extent.center(), Math.min(20, map2.extentZoom(_extent)));
+    injectSegment(e3, t2) {
+      this.options[e3].enabled && this.createParser(e3, t2);
     }
-    function success(geolocation) {
-      _position = geolocation;
-      var coords = _position.coords;
-      _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
-      zoomTo();
-      finish();
+    createParser(e3, t2) {
+      let i3 = new (T.get(e3))(t2, this.options, this.file);
+      return this.parsers[e3] = i3;
     }
-    function error() {
-      if (_position) {
-        zoomTo();
-      } else {
-        context.ui().flash.label(_t.append("geolocate.location_unavailable")).iconName("#iD-icon-geolocate")();
+    createParsers(e3) {
+      for (let t2 of e3) {
+        let { type: e4, chunk: i3 } = t2, n3 = this.options[e4];
+        if (n3 && n3.enabled) {
+          let t3 = this.parsers[e4];
+          t3 && t3.append || t3 || this.createParser(e4, i3);
+        }
       }
-      finish();
     }
-    function finish() {
-      _locating.close();
-      if (_timeoutID) {
-        clearTimeout(_timeoutID);
-      }
-      _timeoutID = void 0;
+    async readSegments(e3) {
+      let t2 = e3.map(this.ensureSegmentChunk);
+      await Promise.all(t2);
     }
-    function updateButtonState() {
-      _button.classed("active", _layer.enabled());
-      _button.attr("aria-pressed", _layer.enabled());
+  };
+  var re2 = class {
+    static findPosition(e3, t2) {
+      let i3 = e3.getUint16(t2 + 2) + 2, n3 = "function" == typeof this.headerLength ? this.headerLength(e3, t2, i3) : this.headerLength, s2 = t2 + n3, r2 = i3 - n3;
+      return { offset: t2, length: i3, headerLength: n3, start: s2, size: r2, end: s2 + r2 };
     }
-    return function(selection2) {
-      if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition)
-        return;
-      _button = selection2.append("button").on("click", click).attr("aria-pressed", false).call(svgIcon("#iD-icon-geolocate", "light")).call(
-        uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _t.append("geolocate.title")).keys([_t("geolocate.key")])
-      );
-      context.keybinding().on(_t("geolocate.key"), click);
-    };
+    static parse(e3, t2 = {}) {
+      return new this(e3, new q({ [this.type]: t2 }), e3).parse();
+    }
+    normalizeInput(e3) {
+      return e3 instanceof I ? e3 : new I(e3);
+    }
+    constructor(e3, t2 = {}, i3) {
+      c(this, "errors", []), c(this, "raw", /* @__PURE__ */ new Map()), c(this, "handleError", (e4) => {
+        if (!this.options.silentErrors) throw e4;
+        this.errors.push(e4.message);
+      }), this.chunk = this.normalizeInput(e3), this.file = i3, this.type = this.constructor.type, this.globalOptions = this.options = t2, this.localOptions = t2[this.type], this.canTranslate = this.localOptions && this.localOptions.translate;
+    }
+    translate() {
+      this.canTranslate && (this.translated = this.translateBlock(this.raw, this.type));
+    }
+    get output() {
+      return this.translated ? this.translated : this.raw ? Object.fromEntries(this.raw) : void 0;
+    }
+    translateBlock(e3, t2) {
+      let i3 = N.get(t2), n3 = B.get(t2), s2 = E.get(t2), r2 = this.options[t2], a2 = r2.reviveValues && !!i3, o2 = r2.translateValues && !!n3, l2 = r2.translateKeys && !!s2, h2 = {};
+      for (let [t3, r3] of e3) a2 && i3.has(t3) ? r3 = i3.get(t3)(r3) : o2 && n3.has(t3) && (r3 = this.translateValue(r3, n3.get(t3))), l2 && s2.has(t3) && (t3 = s2.get(t3) || t3), h2[t3] = r3;
+      return h2;
+    }
+    translateValue(e3, t2) {
+      return t2[e3] || t2.DEFAULT || e3;
+    }
+    assignToOutput(e3, t2) {
+      this.assignObjectToOutput(e3, this.constructor.type, t2);
+    }
+    assignObjectToOutput(e3, t2, i3) {
+      if (this.globalOptions.mergeOutput) return Object.assign(e3, i3);
+      e3[t2] ? Object.assign(e3[t2], i3) : e3[t2] = i3;
+    }
+  };
+  c(re2, "headerLength", 4), c(re2, "type", void 0), c(re2, "multiSegment", false), c(re2, "canHandle", () => false);
+  function ae(e3) {
+    return 192 === e3 || 194 === e3 || 196 === e3 || 219 === e3 || 221 === e3 || 218 === e3 || 254 === e3;
   }
-
-  // modules/ui/panels/background.js
-  function uiPanelBackground(context) {
-    var background = context.background();
-    var _currSourceName = null;
-    var _metadata = {};
-    var _metadataKeys = [
-      "zoom",
-      "vintage",
-      "source",
-      "description",
-      "resolution",
-      "accuracy"
-    ];
-    var debouncedRedraw = debounce_default(redraw, 250);
-    function redraw(selection2) {
-      var source = background.baseLayerSource();
-      if (!source)
-        return;
-      var isDG = source.id.match(/^DigitalGlobe/i) !== null;
-      var sourceLabel = source.label();
-      if (_currSourceName !== sourceLabel) {
-        _currSourceName = sourceLabel;
-        _metadata = {};
+  function oe(e3) {
+    return e3 >= 224 && e3 <= 239;
+  }
+  function le(e3, t2, i3) {
+    for (let [n3, s2] of T) if (s2.canHandle(e3, t2, i3)) return n3;
+  }
+  var he = class extends se {
+    constructor(...e3) {
+      super(...e3), c(this, "appSegments", []), c(this, "jpegSegments", []), c(this, "unknownSegments", []);
+    }
+    static canHandle(e3, t2) {
+      return 65496 === t2;
+    }
+    async parse() {
+      await this.findAppSegments(), await this.readSegments(this.appSegments), this.mergeMultiSegments(), this.createParsers(this.mergedAppSegments || this.appSegments);
+    }
+    setupSegmentFinderArgs(e3) {
+      true === e3 ? (this.findAll = true, this.wanted = new Set(T.keyList())) : (e3 = void 0 === e3 ? T.keyList().filter((e4) => this.options[e4].enabled) : e3.filter((e4) => this.options[e4].enabled && T.has(e4)), this.findAll = false, this.remaining = new Set(e3), this.wanted = new Set(e3)), this.unfinishedMultiSegment = false;
+    }
+    async findAppSegments(e3 = 0, t2) {
+      this.setupSegmentFinderArgs(t2);
+      let { file: i3, findAll: n3, wanted: s2, remaining: r2 } = this;
+      if (!n3 && this.file.chunked && (n3 = Array.from(s2).some((e4) => {
+        let t3 = T.get(e4), i4 = this.options[e4];
+        return t3.multiSegment && i4.multiSegment;
+      }), n3 && await this.file.readWhole()), e3 = this.findAppSegmentsInRange(e3, i3.byteLength), !this.options.onlyTiff && i3.chunked) {
+        let t3 = false;
+        for (; r2.size > 0 && !t3 && (i3.canReadNextChunk || this.unfinishedMultiSegment); ) {
+          let { nextChunkOffset: n4 } = i3, s3 = this.appSegments.some((e4) => !this.file.available(e4.offset || e4.start, e4.length || e4.size));
+          if (t3 = e3 > n4 && !s3 ? !await i3.readNextChunk(e3) : !await i3.readNextChunk(n4), void 0 === (e3 = this.findAppSegmentsInRange(e3, i3.byteLength))) return;
+        }
       }
-      selection2.text("");
-      var list = selection2.append("ul").attr("class", "background-info");
-      list.append("li").call(_currSourceName);
-      _metadataKeys.forEach(function(k) {
-        if (isDG && k === "vintage")
-          return;
-        list.append("li").attr("class", "background-info-list-" + k).classed("hide", !_metadata[k]).call(_t.append("info_panels.background." + k, { suffix: ":" })).append("span").attr("class", "background-info-span-" + k).text(_metadata[k]);
-      });
-      debouncedGetMetadata(selection2);
-      var toggleTiles = context.getDebug("tile") ? "hide_tiles" : "show_tiles";
-      selection2.append("a").call(_t.append("info_panels.background." + toggleTiles)).attr("href", "#").attr("class", "button button-toggle-tiles").on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.setDebug("tile", !context.getDebug("tile"));
-        selection2.call(redraw);
-      });
-      if (isDG) {
-        var key = source.id + "-vintage";
-        var sourceVintage = context.background().findSource(key);
-        var showsVintage = context.background().showsLayer(sourceVintage);
-        var toggleVintage = showsVintage ? "hide_vintage" : "show_vintage";
-        selection2.append("a").call(_t.append("info_panels.background." + toggleVintage)).attr("href", "#").attr("class", "button button-toggle-vintage").on("click", function(d3_event) {
-          d3_event.preventDefault();
-          context.background().toggleOverlayLayer(sourceVintage);
-          selection2.call(redraw);
-        });
+    }
+    findAppSegmentsInRange(e3, t2) {
+      t2 -= 2;
+      let i3, n3, s2, r2, a2, o2, { file: l2, findAll: h2, wanted: u2, remaining: c2, options: f2 } = this;
+      for (; e3 < t2; e3++) if (255 === l2.getUint8(e3)) {
+        if (i3 = l2.getUint8(e3 + 1), oe(i3)) {
+          if (n3 = l2.getUint16(e3 + 2), s2 = le(l2, e3, n3), s2 && u2.has(s2) && (r2 = T.get(s2), a2 = r2.findPosition(l2, e3), o2 = f2[s2], a2.type = s2, this.appSegments.push(a2), !h2 && (r2.multiSegment && o2.multiSegment ? (this.unfinishedMultiSegment = a2.chunkNumber < a2.chunkCount, this.unfinishedMultiSegment || c2.delete(s2)) : c2.delete(s2), 0 === c2.size))) break;
+          f2.recordUnknownSegments && (a2 = re2.findPosition(l2, e3), a2.marker = i3, this.unknownSegments.push(a2)), e3 += n3 + 1;
+        } else if (ae(i3)) {
+          if (n3 = l2.getUint16(e3 + 2), 218 === i3 && false !== f2.stopAfterSos) return;
+          f2.recordJpegSegments && this.jpegSegments.push({ offset: e3, length: n3, marker: i3 }), e3 += n3 + 1;
+        }
       }
-      ["DigitalGlobe-Premium", "DigitalGlobe-Standard"].forEach(function(layerId) {
-        if (source.id !== layerId) {
-          var key2 = layerId + "-vintage";
-          var sourceVintage2 = context.background().findSource(key2);
-          if (context.background().showsLayer(sourceVintage2)) {
-            context.background().toggleOverlayLayer(sourceVintage2);
-          }
+      return e3;
+    }
+    mergeMultiSegments() {
+      if (!this.appSegments.some((e4) => e4.multiSegment)) return;
+      let e3 = function(e4, t2) {
+        let i3, n3, s2, r2 = /* @__PURE__ */ new Map();
+        for (let a2 = 0; a2 < e4.length; a2++) i3 = e4[a2], n3 = i3[t2], r2.has(n3) ? s2 = r2.get(n3) : r2.set(n3, s2 = []), s2.push(i3);
+        return Array.from(r2);
+      }(this.appSegments, "type");
+      this.mergedAppSegments = e3.map(([e4, t2]) => {
+        let i3 = T.get(e4, this.options);
+        if (i3.handleMultiSegments) {
+          return { type: e4, chunk: i3.handleMultiSegments(t2) };
         }
+        return t2[0];
       });
     }
-    var debouncedGetMetadata = debounce_default(getMetadata, 250);
-    function getMetadata(selection2) {
-      var tile = context.container().select(".layer-background img.tile-center");
-      if (tile.empty())
-        return;
-      var sourceName = _currSourceName;
-      var d = tile.datum();
-      var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
-      var center = context.map().center();
-      _metadata.zoom = String(zoom);
-      selection2.selectAll(".background-info-list-zoom").classed("hide", false).selectAll(".background-info-span-zoom").text(_metadata.zoom);
-      if (!d || !d.length >= 3)
-        return;
-      background.baseLayerSource().getMetadata(center, d, function(err, result) {
-        if (err || _currSourceName !== sourceName)
-          return;
-        var vintage = result.vintage;
-        _metadata.vintage = vintage && vintage.range || _t("info_panels.background.unknown");
-        selection2.selectAll(".background-info-list-vintage").classed("hide", false).selectAll(".background-info-span-vintage").text(_metadata.vintage);
-        _metadataKeys.forEach(function(k) {
-          if (k === "zoom" || k === "vintage")
-            return;
-          var val = result[k];
-          _metadata[k] = val;
-          selection2.selectAll(".background-info-list-" + k).classed("hide", !val).selectAll(".background-info-span-" + k).text(val);
-        });
-      });
+    getSegment(e3) {
+      return this.appSegments.find((t2) => t2.type === e3);
     }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.map().on("drawn.info-background", function() {
-        selection2.call(debouncedRedraw);
-      }).on("move.info-background", function() {
-        selection2.call(debouncedGetMetadata);
-      });
-    };
-    panel.off = function() {
-      context.map().on("drawn.info-background", null).on("move.info-background", null);
-    };
-    panel.id = "background";
-    panel.label = _t.append("info_panels.background.title");
-    panel.key = _t("info_panels.background.key");
-    return panel;
-  }
-
-  // modules/ui/panels/history.js
-  function uiPanelHistory(context) {
-    var osm;
-    function displayTimestamp(timestamp) {
-      if (!timestamp)
-        return _t("info_panels.history.unknown");
-      var options2 = {
-        day: "numeric",
-        month: "short",
-        year: "numeric",
-        hour: "numeric",
-        minute: "numeric",
-        second: "numeric"
-      };
-      var d = new Date(timestamp);
-      if (isNaN(d.getTime()))
-        return _t("info_panels.history.unknown");
-      return d.toLocaleString(_mainLocalizer.localeCode(), options2);
+    async getOrFindSegment(e3) {
+      let t2 = this.getSegment(e3);
+      return void 0 === t2 && (await this.findAppSegments(0, [e3]), t2 = this.getSegment(e3)), t2;
     }
-    function displayUser(selection2, userName) {
-      if (!userName) {
-        selection2.append("span").call(_t.append("info_panels.history.unknown"));
-        return;
+  };
+  c(he, "type", "jpeg"), w.set("jpeg", he);
+  var ue = [void 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4];
+  var ce = class extends re2 {
+    parseHeader() {
+      var e3 = this.chunk.getUint16();
+      18761 === e3 ? this.le = true : 19789 === e3 && (this.le = false), this.chunk.le = this.le, this.headerParsed = true;
+    }
+    parseTags(e3, t2, i3 = /* @__PURE__ */ new Map()) {
+      let { pick: n3, skip: s2 } = this.options[t2];
+      n3 = new Set(n3);
+      let r2 = n3.size > 0, a2 = 0 === s2.size, o2 = this.chunk.getUint16(e3);
+      e3 += 2;
+      for (let l2 = 0; l2 < o2; l2++) {
+        let o3 = this.chunk.getUint16(e3);
+        if (r2) {
+          if (n3.has(o3) && (i3.set(o3, this.parseTag(e3, o3, t2)), n3.delete(o3), 0 === n3.size)) break;
+        } else !a2 && s2.has(o3) || i3.set(o3, this.parseTag(e3, o3, t2));
+        e3 += 12;
+      }
+      return i3;
+    }
+    parseTag(e3, t2, i3) {
+      let { chunk: n3 } = this, s2 = n3.getUint16(e3 + 2), r2 = n3.getUint32(e3 + 4), a2 = ue[s2];
+      if (a2 * r2 <= 4 ? e3 += 8 : e3 = n3.getUint32(e3 + 8), (s2 < 1 || s2 > 13) && g2("Invalid TIFF value type. block: ".concat(i3.toUpperCase(), ", tag: ").concat(t2.toString(16), ", type: ").concat(s2, ", offset ").concat(e3)), e3 > n3.byteLength && g2("Invalid TIFF value offset. block: ".concat(i3.toUpperCase(), ", tag: ").concat(t2.toString(16), ", type: ").concat(s2, ", offset ").concat(e3, " is outside of chunk size ").concat(n3.byteLength)), 1 === s2) return n3.getUint8Array(e3, r2);
+      if (2 === s2) return m(n3.getString(e3, r2));
+      if (7 === s2) return n3.getUint8Array(e3, r2);
+      if (1 === r2) return this.parseTagValue(s2, e3);
+      {
+        let t3 = new (function(e4) {
+          switch (e4) {
+            case 1:
+              return Uint8Array;
+            case 3:
+              return Uint16Array;
+            case 4:
+              return Uint32Array;
+            case 5:
+              return Array;
+            case 6:
+              return Int8Array;
+            case 8:
+              return Int16Array;
+            case 9:
+              return Int32Array;
+            case 10:
+              return Array;
+            case 11:
+              return Float32Array;
+            case 12:
+              return Float64Array;
+            default:
+              return Array;
+          }
+        }(s2))(r2), i4 = a2;
+        for (let n4 = 0; n4 < r2; n4++) t3[n4] = this.parseTagValue(s2, e3), e3 += i4;
+        return t3;
+      }
+    }
+    parseTagValue(e3, t2) {
+      let { chunk: i3 } = this;
+      switch (e3) {
+        case 1:
+          return i3.getUint8(t2);
+        case 3:
+          return i3.getUint16(t2);
+        case 4:
+          return i3.getUint32(t2);
+        case 5:
+          return i3.getUint32(t2) / i3.getUint32(t2 + 4);
+        case 6:
+          return i3.getInt8(t2);
+        case 8:
+          return i3.getInt16(t2);
+        case 9:
+          return i3.getInt32(t2);
+        case 10:
+          return i3.getInt32(t2) / i3.getInt32(t2 + 4);
+        case 11:
+          return i3.getFloat(t2);
+        case 12:
+          return i3.getDouble(t2);
+        case 13:
+          return i3.getUint32(t2);
+        default:
+          g2("Invalid tiff type ".concat(e3));
       }
-      selection2.append("span").attr("class", "user-name").text(userName);
-      var links = selection2.append("div").attr("class", "links");
-      if (osm) {
-        links.append("a").attr("class", "user-osm-link").attr("href", osm.userURL(userName)).attr("target", "_blank").call(_t.append("info_panels.history.profile_link"));
+    }
+  };
+  var fe = class extends ce {
+    static canHandle(e3, t2) {
+      return 225 === e3.getUint8(t2 + 1) && 1165519206 === e3.getUint32(t2 + 4) && 0 === e3.getUint16(t2 + 8);
+    }
+    async parse() {
+      this.parseHeader();
+      let { options: e3 } = this;
+      return e3.ifd0.enabled && await this.parseIfd0Block(), e3.exif.enabled && await this.safeParse("parseExifBlock"), e3.gps.enabled && await this.safeParse("parseGpsBlock"), e3.interop.enabled && await this.safeParse("parseInteropBlock"), e3.ifd1.enabled && await this.safeParse("parseThumbnailBlock"), this.createOutput();
+    }
+    safeParse(e3) {
+      let t2 = this[e3]();
+      return void 0 !== t2.catch && (t2 = t2.catch(this.handleError)), t2;
+    }
+    findIfd0Offset() {
+      void 0 === this.ifd0Offset && (this.ifd0Offset = this.chunk.getUint32(4));
+    }
+    findIfd1Offset() {
+      if (void 0 === this.ifd1Offset) {
+        this.findIfd0Offset();
+        let e3 = this.chunk.getUint16(this.ifd0Offset), t2 = this.ifd0Offset + 2 + 12 * e3;
+        this.ifd1Offset = this.chunk.getUint32(t2);
+      }
+    }
+    parseBlock(e3, t2) {
+      let i3 = /* @__PURE__ */ new Map();
+      return this[t2] = i3, this.parseTags(e3, t2, i3), i3;
+    }
+    async parseIfd0Block() {
+      if (this.ifd0) return;
+      let { file: e3 } = this;
+      this.findIfd0Offset(), this.ifd0Offset < 8 && g2("Malformed EXIF data"), !e3.chunked && this.ifd0Offset > e3.byteLength && g2("IFD0 offset points to outside of file.\nthis.ifd0Offset: ".concat(this.ifd0Offset, ", file.byteLength: ").concat(e3.byteLength)), e3.tiff && await e3.ensureChunk(this.ifd0Offset, S(this.options));
+      let t2 = this.parseBlock(this.ifd0Offset, "ifd0");
+      return 0 !== t2.size ? (this.exifOffset = t2.get(34665), this.interopOffset = t2.get(40965), this.gpsOffset = t2.get(34853), this.xmp = t2.get(700), this.iptc = t2.get(33723), this.icc = t2.get(34675), this.options.sanitize && (t2.delete(34665), t2.delete(40965), t2.delete(34853), t2.delete(700), t2.delete(33723), t2.delete(34675)), t2) : void 0;
+    }
+    async parseExifBlock() {
+      if (this.exif) return;
+      if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.exifOffset) return;
+      this.file.tiff && await this.file.ensureChunk(this.exifOffset, S(this.options));
+      let e3 = this.parseBlock(this.exifOffset, "exif");
+      return this.interopOffset || (this.interopOffset = e3.get(40965)), this.makerNote = e3.get(37500), this.userComment = e3.get(37510), this.options.sanitize && (e3.delete(40965), e3.delete(37500), e3.delete(37510)), this.unpack(e3, 41728), this.unpack(e3, 41729), e3;
+    }
+    unpack(e3, t2) {
+      let i3 = e3.get(t2);
+      i3 && 1 === i3.length && e3.set(t2, i3[0]);
+    }
+    async parseGpsBlock() {
+      if (this.gps) return;
+      if (this.ifd0 || await this.parseIfd0Block(), void 0 === this.gpsOffset) return;
+      let e3 = this.parseBlock(this.gpsOffset, "gps");
+      return e3 && e3.has(2) && e3.has(4) && (e3.set("latitude", de(...e3.get(2), e3.get(1))), e3.set("longitude", de(...e3.get(4), e3.get(3)))), e3;
+    }
+    async parseInteropBlock() {
+      if (!this.interop && (this.ifd0 || await this.parseIfd0Block(), void 0 !== this.interopOffset || this.exif || await this.parseExifBlock(), void 0 !== this.interopOffset)) return this.parseBlock(this.interopOffset, "interop");
+    }
+    async parseThumbnailBlock(e3 = false) {
+      if (!this.ifd1 && !this.ifd1Parsed && (!this.options.mergeOutput || e3)) return this.findIfd1Offset(), this.ifd1Offset > 0 && (this.parseBlock(this.ifd1Offset, "ifd1"), this.ifd1Parsed = true), this.ifd1;
+    }
+    async extractThumbnail() {
+      if (this.headerParsed || this.parseHeader(), this.ifd1Parsed || await this.parseThumbnailBlock(true), void 0 === this.ifd1) return;
+      let e3 = this.ifd1.get(513), t2 = this.ifd1.get(514);
+      return this.chunk.getUint8Array(e3, t2);
+    }
+    get image() {
+      return this.ifd0;
+    }
+    get thumbnail() {
+      return this.ifd1;
+    }
+    createOutput() {
+      let e3, t2, i3, n3 = {};
+      for (t2 of H) if (e3 = this[t2], !p(e3)) if (i3 = this.canTranslate ? this.translateBlock(e3, t2) : Object.fromEntries(e3), this.options.mergeOutput) {
+        if ("ifd1" === t2) continue;
+        Object.assign(n3, i3);
+      } else n3[t2] = i3;
+      return this.makerNote && (n3.makerNote = this.makerNote), this.userComment && (n3.userComment = this.userComment), n3;
+    }
+    assignToOutput(e3, t2) {
+      if (this.globalOptions.mergeOutput) Object.assign(e3, t2);
+      else for (let [i3, n3] of Object.entries(t2)) this.assignObjectToOutput(e3, i3, n3);
+    }
+  };
+  function de(e3, t2, i3, n3) {
+    var s2 = e3 + t2 / 60 + i3 / 3600;
+    return "S" !== n3 && "W" !== n3 || (s2 *= -1), s2;
+  }
+  c(fe, "type", "tiff"), c(fe, "headerLength", 10), T.set("tiff", fe);
+  var pe = Object.freeze({ __proto__: null, default: ne, Exifr: te, fileParsers: w, segmentParsers: T, fileReaders: A, tagKeys: E, tagValues: B, tagRevivers: N, createDictionary: U, extendDictionary: F, fetchUrlAsArrayBuffer: M, readBlobAsArrayBuffer: R, chunkedProps: G, otherSegments: V, segments: z, tiffBlocks: H, segmentsAndBlocks: j, tiffExtractables: W, inheritables: K, allFormatters: X, Options: q, parse: ie });
+  var ge = { ifd0: false, ifd1: false, exif: false, gps: false, interop: false, sanitize: false, reviveValues: true, translateKeys: false, translateValues: false, mergeOutput: false };
+  var me = Object.assign({}, ge, { firstChunkSize: 4e4, gps: [1, 2, 3, 4] });
+  async function Se(e3) {
+    let t2 = new te(me);
+    await t2.read(e3);
+    let i3 = await t2.parse();
+    if (i3 && i3.gps) {
+      let { latitude: e4, longitude: t3 } = i3.gps;
+      return { latitude: e4, longitude: t3 };
+    }
+  }
+  var Ce = Object.assign({}, ge, { tiff: false, ifd1: true, mergeOutput: false });
+  async function ye(e3) {
+    let t2 = new te(Ce);
+    await t2.read(e3);
+    let i3 = await t2.extractThumbnail();
+    return i3 && a ? s.from(i3) : i3;
+  }
+  async function be(e3) {
+    let t2 = await this.thumbnail(e3);
+    if (void 0 !== t2) {
+      let e4 = new Blob([t2]);
+      return URL.createObjectURL(e4);
+    }
+  }
+  var Ie = Object.assign({}, ge, { firstChunkSize: 4e4, ifd0: [274] });
+  async function Pe(e3) {
+    let t2 = new te(Ie);
+    await t2.read(e3);
+    let i3 = await t2.parse();
+    if (i3 && i3.ifd0) return i3.ifd0[274];
+  }
+  var ke = Object.freeze({ 1: { dimensionSwapped: false, scaleX: 1, scaleY: 1, deg: 0, rad: 0 }, 2: { dimensionSwapped: false, scaleX: -1, scaleY: 1, deg: 0, rad: 0 }, 3: { dimensionSwapped: false, scaleX: 1, scaleY: 1, deg: 180, rad: 180 * Math.PI / 180 }, 4: { dimensionSwapped: false, scaleX: -1, scaleY: 1, deg: 180, rad: 180 * Math.PI / 180 }, 5: { dimensionSwapped: true, scaleX: 1, scaleY: -1, deg: 90, rad: 90 * Math.PI / 180 }, 6: { dimensionSwapped: true, scaleX: 1, scaleY: 1, deg: 90, rad: 90 * Math.PI / 180 }, 7: { dimensionSwapped: true, scaleX: 1, scaleY: -1, deg: 270, rad: 270 * Math.PI / 180 }, 8: { dimensionSwapped: true, scaleX: 1, scaleY: 1, deg: 270, rad: 270 * Math.PI / 180 } });
+  var we = true;
+  var Te = true;
+  if ("object" == typeof navigator) {
+    let e3 = navigator.userAgent;
+    if (e3.includes("iPad") || e3.includes("iPhone")) {
+      let t2 = e3.match(/OS (\d+)_(\d+)/);
+      if (t2) {
+        let [, e4, i3] = t2, n3 = Number(e4) + 0.1 * Number(i3);
+        we = n3 < 13.4, Te = false;
+      }
+    } else if (e3.includes("OS X 10")) {
+      let [, t2] = e3.match(/OS X 10[_.](\d+)/);
+      we = Te = Number(t2) < 15;
+    }
+    if (e3.includes("Chrome/")) {
+      let [, t2] = e3.match(/Chrome\/(\d+)/);
+      we = Te = Number(t2) < 81;
+    } else if (e3.includes("Firefox/")) {
+      let [, t2] = e3.match(/Firefox\/(\d+)/);
+      we = Te = Number(t2) < 77;
+    }
+  }
+  async function Ae(e3) {
+    let t2 = await Pe(e3);
+    return Object.assign({ canvas: we, css: Te }, ke[t2]);
+  }
+  var De = class extends I {
+    constructor(...e3) {
+      super(...e3), c(this, "ranges", new Oe()), 0 !== this.byteLength && this.ranges.add(0, this.byteLength);
+    }
+    _tryExtend(e3, t2, i3) {
+      if (0 === e3 && 0 === this.byteLength && i3) {
+        let e4 = new DataView(i3.buffer || i3, i3.byteOffset, i3.byteLength);
+        this._swapDataView(e4);
+      } else {
+        let i4 = e3 + t2;
+        if (i4 > this.byteLength) {
+          let { dataView: e4 } = this._extend(i4);
+          this._swapDataView(e4);
+        }
       }
-      links.append("a").attr("class", "user-hdyc-link").attr("href", "https://hdyc.neis-one.org/?" + userName).attr("target", "_blank").attr("tabindex", -1).text("HDYC");
     }
-    function displayChangeset(selection2, changeset) {
-      if (!changeset) {
-        selection2.append("span").call(_t.append("info_panels.history.unknown"));
-        return;
+    _extend(e3) {
+      let t2;
+      t2 = a ? s.allocUnsafe(e3) : new Uint8Array(e3);
+      let i3 = new DataView(t2.buffer, t2.byteOffset, t2.byteLength);
+      return t2.set(new Uint8Array(this.buffer, this.byteOffset, this.byteLength), 0), { uintView: t2, dataView: i3 };
+    }
+    subarray(e3, t2, i3 = false) {
+      return t2 = t2 || this._lengthToEnd(e3), i3 && this._tryExtend(e3, t2), this.ranges.add(e3, t2), super.subarray(e3, t2);
+    }
+    set(e3, t2, i3 = false) {
+      i3 && this._tryExtend(t2, e3.byteLength, e3);
+      let n3 = super.set(e3, t2);
+      return this.ranges.add(t2, n3.byteLength), n3;
+    }
+    async ensureChunk(e3, t2) {
+      this.chunked && (this.ranges.available(e3, t2) || await this.readChunk(e3, t2));
+    }
+    available(e3, t2) {
+      return this.ranges.available(e3, t2);
+    }
+  };
+  var Oe = class {
+    constructor() {
+      c(this, "list", []);
+    }
+    get length() {
+      return this.list.length;
+    }
+    add(e3, t2, i3 = 0) {
+      let n3 = e3 + t2, s2 = this.list.filter((t3) => xe(e3, t3.offset, n3) || xe(e3, t3.end, n3));
+      if (s2.length > 0) {
+        e3 = Math.min(e3, ...s2.map((e4) => e4.offset)), n3 = Math.max(n3, ...s2.map((e4) => e4.end)), t2 = n3 - e3;
+        let i4 = s2.shift();
+        i4.offset = e3, i4.length = t2, i4.end = n3, this.list = this.list.filter((e4) => !s2.includes(e4));
+      } else this.list.push({ offset: e3, length: t2, end: n3 });
+    }
+    available(e3, t2) {
+      let i3 = e3 + t2;
+      return this.list.some((t3) => t3.offset <= e3 && i3 <= t3.end);
+    }
+  };
+  function xe(e3, t2, i3) {
+    return e3 <= t2 && t2 <= i3;
+  }
+  var ve = class extends De {
+    constructor(e3, t2) {
+      super(0), c(this, "chunksRead", 0), this.input = e3, this.options = t2;
+    }
+    async readWhole() {
+      this.chunked = false, await this.readChunk(this.nextChunkOffset);
+    }
+    async readChunked() {
+      this.chunked = true, await this.readChunk(0, this.options.firstChunkSize);
+    }
+    async readNextChunk(e3 = this.nextChunkOffset) {
+      if (this.fullyRead) return this.chunksRead++, false;
+      let t2 = this.options.chunkSize, i3 = await this.readChunk(e3, t2);
+      return !!i3 && i3.byteLength === t2;
+    }
+    async readChunk(e3, t2) {
+      if (this.chunksRead++, 0 !== (t2 = this.safeWrapAddress(e3, t2))) return this._readChunk(e3, t2);
+    }
+    safeWrapAddress(e3, t2) {
+      return void 0 !== this.size && e3 + t2 > this.size ? Math.max(0, this.size - e3) : t2;
+    }
+    get nextChunkOffset() {
+      if (0 !== this.ranges.list.length) return this.ranges.list[0].length;
+    }
+    get canReadNextChunk() {
+      return this.chunksRead < this.options.chunkLimit;
+    }
+    get fullyRead() {
+      return void 0 !== this.size && this.nextChunkOffset === this.size;
+    }
+    read() {
+      return this.options.chunked ? this.readChunked() : this.readWhole();
+    }
+    close() {
+    }
+  };
+  A.set("blob", class extends ve {
+    async readWhole() {
+      this.chunked = false;
+      let e3 = await R(this.input);
+      this._swapArrayBuffer(e3);
+    }
+    readChunked() {
+      return this.chunked = true, this.size = this.input.size, super.readChunked();
+    }
+    async _readChunk(e3, t2) {
+      let i3 = t2 ? e3 + t2 : void 0, n3 = this.input.slice(e3, i3), s2 = await R(n3);
+      return this.set(s2, e3, true);
+    }
+  });
+  var Me = Object.freeze({ __proto__: null, default: pe, Exifr: te, fileParsers: w, segmentParsers: T, fileReaders: A, tagKeys: E, tagValues: B, tagRevivers: N, createDictionary: U, extendDictionary: F, fetchUrlAsArrayBuffer: M, readBlobAsArrayBuffer: R, chunkedProps: G, otherSegments: V, segments: z, tiffBlocks: H, segmentsAndBlocks: j, tiffExtractables: W, inheritables: K, allFormatters: X, Options: q, parse: ie, gpsOnlyOptions: me, gps: Se, thumbnailOnlyOptions: Ce, thumbnail: ye, thumbnailUrl: be, orientationOnlyOptions: Ie, orientation: Pe, rotations: ke, get rotateCanvas() {
+    return we;
+  }, get rotateCss() {
+    return Te;
+  }, rotation: Ae });
+  A.set("url", class extends ve {
+    async readWhole() {
+      this.chunked = false;
+      let e3 = await M(this.input);
+      e3 instanceof ArrayBuffer ? this._swapArrayBuffer(e3) : e3 instanceof Uint8Array && this._swapBuffer(e3);
+    }
+    async _readChunk(e3, t2) {
+      let i3 = t2 ? e3 + t2 - 1 : void 0, n3 = this.options.httpHeaders || {};
+      (e3 || i3) && (n3.range = "bytes=".concat([e3, i3].join("-")));
+      let s2 = await h(this.input, { headers: n3 }), r2 = await s2.arrayBuffer(), a2 = r2.byteLength;
+      if (416 !== s2.status) return a2 !== t2 && (this.size = e3 + a2), this.set(r2, e3, true);
+    }
+  });
+  I.prototype.getUint64 = function(e3) {
+    let t2 = this.getUint32(e3), i3 = this.getUint32(e3 + 4);
+    return t2 < 1048575 ? t2 << 32 | i3 : void 0 !== typeof r ? (console.warn("Using BigInt because of type 64uint but JS can only handle 53b numbers."), r(t2) << r(32) | r(i3)) : void g2("Trying to read 64b value but JS can only handle 53b numbers.");
+  };
+  var Re = class extends se {
+    parseBoxes(e3 = 0) {
+      let t2 = [];
+      for (; e3 < this.file.byteLength - 4; ) {
+        let i3 = this.parseBoxHead(e3);
+        if (t2.push(i3), 0 === i3.length) break;
+        e3 += i3.length;
       }
-      selection2.append("span").attr("class", "changeset-id").text(changeset);
-      var links = selection2.append("div").attr("class", "links");
-      if (osm) {
-        links.append("a").attr("class", "changeset-osm-link").attr("href", osm.changesetURL(changeset)).attr("target", "_blank").call(_t.append("info_panels.history.changeset_link"));
+      return t2;
+    }
+    parseSubBoxes(e3) {
+      e3.boxes = this.parseBoxes(e3.start);
+    }
+    findBox(e3, t2) {
+      return void 0 === e3.boxes && this.parseSubBoxes(e3), e3.boxes.find((e4) => e4.kind === t2);
+    }
+    parseBoxHead(e3) {
+      let t2 = this.file.getUint32(e3), i3 = this.file.getString(e3 + 4, 4), n3 = e3 + 8;
+      return 1 === t2 && (t2 = this.file.getUint64(e3 + 8), n3 += 8), { offset: e3, length: t2, kind: i3, start: n3 };
+    }
+    parseBoxFullHead(e3) {
+      if (void 0 !== e3.version) return;
+      let t2 = this.file.getUint32(e3.start);
+      e3.version = t2 >> 24, e3.start += 4;
+    }
+  };
+  var Le = class extends Re {
+    static canHandle(e3, t2) {
+      if (0 !== t2) return false;
+      let i3 = e3.getUint16(2);
+      if (i3 > 50) return false;
+      let n3 = 16, s2 = [];
+      for (; n3 < i3; ) s2.push(e3.getString(n3, 4)), n3 += 4;
+      return s2.includes(this.type);
+    }
+    async parse() {
+      let e3 = this.file.getUint32(0), t2 = this.parseBoxHead(e3);
+      for (; "meta" !== t2.kind; ) e3 += t2.length, await this.file.ensureChunk(e3, 16), t2 = this.parseBoxHead(e3);
+      await this.file.ensureChunk(t2.offset, t2.length), this.parseBoxFullHead(t2), this.parseSubBoxes(t2), this.options.icc.enabled && await this.findIcc(t2), this.options.tiff.enabled && await this.findExif(t2);
+    }
+    async registerSegment(e3, t2, i3) {
+      await this.file.ensureChunk(t2, i3);
+      let n3 = this.file.subarray(t2, i3);
+      this.createParser(e3, n3);
+    }
+    async findIcc(e3) {
+      let t2 = this.findBox(e3, "iprp");
+      if (void 0 === t2) return;
+      let i3 = this.findBox(t2, "ipco");
+      if (void 0 === i3) return;
+      let n3 = this.findBox(i3, "colr");
+      void 0 !== n3 && await this.registerSegment("icc", n3.offset + 12, n3.length);
+    }
+    async findExif(e3) {
+      let t2 = this.findBox(e3, "iinf");
+      if (void 0 === t2) return;
+      let i3 = this.findBox(e3, "iloc");
+      if (void 0 === i3) return;
+      let n3 = this.findExifLocIdInIinf(t2), s2 = this.findExtentInIloc(i3, n3);
+      if (void 0 === s2) return;
+      let [r2, a2] = s2;
+      await this.file.ensureChunk(r2, a2);
+      let o2 = 4 + this.file.getUint32(r2);
+      r2 += o2, a2 -= o2, await this.registerSegment("tiff", r2, a2);
+    }
+    findExifLocIdInIinf(e3) {
+      this.parseBoxFullHead(e3);
+      let t2, i3, n3, s2, r2 = e3.start, a2 = this.file.getUint16(r2);
+      for (r2 += 2; a2--; ) {
+        if (t2 = this.parseBoxHead(r2), this.parseBoxFullHead(t2), i3 = t2.start, t2.version >= 2 && (n3 = 3 === t2.version ? 4 : 2, s2 = this.file.getString(i3 + n3 + 2, 4), "Exif" === s2)) return this.file.getUintBytes(i3, n3);
+        r2 += t2.length;
+      }
+    }
+    get8bits(e3) {
+      let t2 = this.file.getUint8(e3);
+      return [t2 >> 4, 15 & t2];
+    }
+    findExtentInIloc(e3, t2) {
+      this.parseBoxFullHead(e3);
+      let i3 = e3.start, [n3, s2] = this.get8bits(i3++), [r2, a2] = this.get8bits(i3++), o2 = 2 === e3.version ? 4 : 2, l2 = 1 === e3.version || 2 === e3.version ? 2 : 0, h2 = a2 + n3 + s2, u2 = 2 === e3.version ? 4 : 2, c2 = this.file.getUintBytes(i3, u2);
+      for (i3 += u2; c2--; ) {
+        let e4 = this.file.getUintBytes(i3, o2);
+        i3 += o2 + l2 + 2 + r2;
+        let u3 = this.file.getUint16(i3);
+        if (i3 += 2, e4 === t2) return u3 > 1 && console.warn("ILOC box has more than one extent but we're only processing one\nPlease create an issue at https://github.com/MikeKovarik/exifr with this file"), [this.file.getUintBytes(i3 + a2, n3), this.file.getUintBytes(i3 + a2 + n3, s2)];
+        i3 += u3 * h2;
       }
-      links.append("a").attr("class", "changeset-osmcha-link").attr("href", "https://osmcha.org/changesets/" + changeset).attr("target", "_blank").text("OSMCha");
-      links.append("a").attr("class", "changeset-achavi-link").attr("href", "https://overpass-api.de/achavi/?changeset=" + changeset).attr("target", "_blank").text("Achavi");
     }
-    function redraw(selection2) {
-      var selectedNoteID = context.selectedNoteID();
-      osm = context.connection();
-      var selected, note, entity;
-      if (selectedNoteID && osm) {
-        selected = [_t.html("note.note") + " " + selectedNoteID];
-        note = osm.getNote(selectedNoteID);
-      } else {
-        selected = context.selectedIDs().filter(function(e) {
-          return context.hasEntity(e);
+  };
+  var Ue = class extends Le {
+  };
+  c(Ue, "type", "heic");
+  var Fe = class extends Le {
+  };
+  c(Fe, "type", "avif"), w.set("heic", Ue), w.set("avif", Fe), U(E, ["ifd0", "ifd1"], [[256, "ImageWidth"], [257, "ImageHeight"], [258, "BitsPerSample"], [259, "Compression"], [262, "PhotometricInterpretation"], [270, "ImageDescription"], [271, "Make"], [272, "Model"], [273, "StripOffsets"], [274, "Orientation"], [277, "SamplesPerPixel"], [278, "RowsPerStrip"], [279, "StripByteCounts"], [282, "XResolution"], [283, "YResolution"], [284, "PlanarConfiguration"], [296, "ResolutionUnit"], [301, "TransferFunction"], [305, "Software"], [306, "ModifyDate"], [315, "Artist"], [316, "HostComputer"], [317, "Predictor"], [318, "WhitePoint"], [319, "PrimaryChromaticities"], [513, "ThumbnailOffset"], [514, "ThumbnailLength"], [529, "YCbCrCoefficients"], [530, "YCbCrSubSampling"], [531, "YCbCrPositioning"], [532, "ReferenceBlackWhite"], [700, "ApplicationNotes"], [33432, "Copyright"], [33723, "IPTC"], [34665, "ExifIFD"], [34675, "ICC"], [34853, "GpsIFD"], [330, "SubIFD"], [40965, "InteropIFD"], [40091, "XPTitle"], [40092, "XPComment"], [40093, "XPAuthor"], [40094, "XPKeywords"], [40095, "XPSubject"]]), U(E, "exif", [[33434, "ExposureTime"], [33437, "FNumber"], [34850, "ExposureProgram"], [34852, "SpectralSensitivity"], [34855, "ISO"], [34858, "TimeZoneOffset"], [34859, "SelfTimerMode"], [34864, "SensitivityType"], [34865, "StandardOutputSensitivity"], [34866, "RecommendedExposureIndex"], [34867, "ISOSpeed"], [34868, "ISOSpeedLatitudeyyy"], [34869, "ISOSpeedLatitudezzz"], [36864, "ExifVersion"], [36867, "DateTimeOriginal"], [36868, "CreateDate"], [36873, "GooglePlusUploadCode"], [36880, "OffsetTime"], [36881, "OffsetTimeOriginal"], [36882, "OffsetTimeDigitized"], [37121, "ComponentsConfiguration"], [37122, "CompressedBitsPerPixel"], [37377, "ShutterSpeedValue"], [37378, "ApertureValue"], [37379, "BrightnessValue"], [37380, "ExposureCompensation"], [37381, "MaxApertureValue"], [37382, "SubjectDistance"], [37383, "MeteringMode"], [37384, "LightSource"], [37385, "Flash"], [37386, "FocalLength"], [37393, "ImageNumber"], [37394, "SecurityClassification"], [37395, "ImageHistory"], [37396, "SubjectArea"], [37500, "MakerNote"], [37510, "UserComment"], [37520, "SubSecTime"], [37521, "SubSecTimeOriginal"], [37522, "SubSecTimeDigitized"], [37888, "AmbientTemperature"], [37889, "Humidity"], [37890, "Pressure"], [37891, "WaterDepth"], [37892, "Acceleration"], [37893, "CameraElevationAngle"], [40960, "FlashpixVersion"], [40961, "ColorSpace"], [40962, "ExifImageWidth"], [40963, "ExifImageHeight"], [40964, "RelatedSoundFile"], [41483, "FlashEnergy"], [41486, "FocalPlaneXResolution"], [41487, "FocalPlaneYResolution"], [41488, "FocalPlaneResolutionUnit"], [41492, "SubjectLocation"], [41493, "ExposureIndex"], [41495, "SensingMethod"], [41728, "FileSource"], [41729, "SceneType"], [41730, "CFAPattern"], [41985, "CustomRendered"], [41986, "ExposureMode"], [41987, "WhiteBalance"], [41988, "DigitalZoomRatio"], [41989, "FocalLengthIn35mmFormat"], [41990, "SceneCaptureType"], [41991, "GainControl"], [41992, "Contrast"], [41993, "Saturation"], [41994, "Sharpness"], [41996, "SubjectDistanceRange"], [42016, "ImageUniqueID"], [42032, "OwnerName"], [42033, "SerialNumber"], [42034, "LensInfo"], [42035, "LensMake"], [42036, "LensModel"], [42037, "LensSerialNumber"], [42080, "CompositeImage"], [42081, "CompositeImageCount"], [42082, "CompositeImageExposureTimes"], [42240, "Gamma"], [59932, "Padding"], [59933, "OffsetSchema"], [65e3, "OwnerName"], [65001, "SerialNumber"], [65002, "Lens"], [65100, "RawFile"], [65101, "Converter"], [65102, "WhiteBalance"], [65105, "Exposure"], [65106, "Shadows"], [65107, "Brightness"], [65108, "Contrast"], [65109, "Saturation"], [65110, "Sharpness"], [65111, "Smoothness"], [65112, "MoireFilter"], [40965, "InteropIFD"]]), U(E, "gps", [[0, "GPSVersionID"], [1, "GPSLatitudeRef"], [2, "GPSLatitude"], [3, "GPSLongitudeRef"], [4, "GPSLongitude"], [5, "GPSAltitudeRef"], [6, "GPSAltitude"], [7, "GPSTimeStamp"], [8, "GPSSatellites"], [9, "GPSStatus"], [10, "GPSMeasureMode"], [11, "GPSDOP"], [12, "GPSSpeedRef"], [13, "GPSSpeed"], [14, "GPSTrackRef"], [15, "GPSTrack"], [16, "GPSImgDirectionRef"], [17, "GPSImgDirection"], [18, "GPSMapDatum"], [19, "GPSDestLatitudeRef"], [20, "GPSDestLatitude"], [21, "GPSDestLongitudeRef"], [22, "GPSDestLongitude"], [23, "GPSDestBearingRef"], [24, "GPSDestBearing"], [25, "GPSDestDistanceRef"], [26, "GPSDestDistance"], [27, "GPSProcessingMethod"], [28, "GPSAreaInformation"], [29, "GPSDateStamp"], [30, "GPSDifferential"], [31, "GPSHPositioningError"]]), U(B, ["ifd0", "ifd1"], [[274, { 1: "Horizontal (normal)", 2: "Mirror horizontal", 3: "Rotate 180", 4: "Mirror vertical", 5: "Mirror horizontal and rotate 270 CW", 6: "Rotate 90 CW", 7: "Mirror horizontal and rotate 90 CW", 8: "Rotate 270 CW" }], [296, { 1: "None", 2: "inches", 3: "cm" }]]);
+  var Ee = U(B, "exif", [[34850, { 0: "Not defined", 1: "Manual", 2: "Normal program", 3: "Aperture priority", 4: "Shutter priority", 5: "Creative program", 6: "Action program", 7: "Portrait mode", 8: "Landscape mode" }], [37121, { 0: "-", 1: "Y", 2: "Cb", 3: "Cr", 4: "R", 5: "G", 6: "B" }], [37383, { 0: "Unknown", 1: "Average", 2: "CenterWeightedAverage", 3: "Spot", 4: "MultiSpot", 5: "Pattern", 6: "Partial", 255: "Other" }], [37384, { 0: "Unknown", 1: "Daylight", 2: "Fluorescent", 3: "Tungsten (incandescent light)", 4: "Flash", 9: "Fine weather", 10: "Cloudy weather", 11: "Shade", 12: "Daylight fluorescent (D 5700 - 7100K)", 13: "Day white fluorescent (N 4600 - 5400K)", 14: "Cool white fluorescent (W 3900 - 4500K)", 15: "White fluorescent (WW 3200 - 3700K)", 17: "Standard light A", 18: "Standard light B", 19: "Standard light C", 20: "D55", 21: "D65", 22: "D75", 23: "D50", 24: "ISO studio tungsten", 255: "Other" }], [37385, { 0: "Flash did not fire", 1: "Flash fired", 5: "Strobe return light not detected", 7: "Strobe return light detected", 9: "Flash fired, compulsory flash mode", 13: "Flash fired, compulsory flash mode, return light not detected", 15: "Flash fired, compulsory flash mode, return light detected", 16: "Flash did not fire, compulsory flash mode", 24: "Flash did not fire, auto mode", 25: "Flash fired, auto mode", 29: "Flash fired, auto mode, return light not detected", 31: "Flash fired, auto mode, return light detected", 32: "No flash function", 65: "Flash fired, red-eye reduction mode", 69: "Flash fired, red-eye reduction mode, return light not detected", 71: "Flash fired, red-eye reduction mode, return light detected", 73: "Flash fired, compulsory flash mode, red-eye reduction mode", 77: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected", 79: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected", 89: "Flash fired, auto mode, red-eye reduction mode", 93: "Flash fired, auto mode, return light not detected, red-eye reduction mode", 95: "Flash fired, auto mode, return light detected, red-eye reduction mode" }], [41495, { 1: "Not defined", 2: "One-chip color area sensor", 3: "Two-chip color area sensor", 4: "Three-chip color area sensor", 5: "Color sequential area sensor", 7: "Trilinear sensor", 8: "Color sequential linear sensor" }], [41728, { 1: "Film Scanner", 2: "Reflection Print Scanner", 3: "Digital Camera" }], [41729, { 1: "Directly photographed" }], [41985, { 0: "Normal", 1: "Custom", 2: "HDR (no original saved)", 3: "HDR (original saved)", 4: "Original (for HDR)", 6: "Panorama", 7: "Portrait HDR", 8: "Portrait" }], [41986, { 0: "Auto", 1: "Manual", 2: "Auto bracket" }], [41987, { 0: "Auto", 1: "Manual" }], [41990, { 0: "Standard", 1: "Landscape", 2: "Portrait", 3: "Night", 4: "Other" }], [41991, { 0: "None", 1: "Low gain up", 2: "High gain up", 3: "Low gain down", 4: "High gain down" }], [41996, { 0: "Unknown", 1: "Macro", 2: "Close", 3: "Distant" }], [42080, { 0: "Unknown", 1: "Not a Composite Image", 2: "General Composite Image", 3: "Composite Image Captured While Shooting" }]]);
+  var Be = { 1: "No absolute unit of measurement", 2: "Inch", 3: "Centimeter" };
+  Ee.set(37392, Be), Ee.set(41488, Be);
+  var Ne = { 0: "Normal", 1: "Low", 2: "High" };
+  function Ge(e3) {
+    return "object" == typeof e3 && void 0 !== e3.length ? e3[0] : e3;
+  }
+  function Ve(e3) {
+    let t2 = Array.from(e3).slice(1);
+    return t2[1] > 15 && (t2 = t2.map((e4) => String.fromCharCode(e4))), "0" !== t2[2] && 0 !== t2[2] || t2.pop(), t2.join(".");
+  }
+  function ze(e3) {
+    if ("string" == typeof e3) {
+      var [t2, i3, n3, s2, r2, a2] = e3.trim().split(/[-: ]/g).map(Number), o2 = new Date(t2, i3 - 1, n3);
+      return Number.isNaN(s2) || Number.isNaN(r2) || Number.isNaN(a2) || (o2.setHours(s2), o2.setMinutes(r2), o2.setSeconds(a2)), Number.isNaN(+o2) ? e3 : o2;
+    }
+  }
+  function He(e3) {
+    if ("string" == typeof e3) return e3;
+    let t2 = [];
+    if (0 === e3[1] && 0 === e3[e3.length - 1]) for (let i3 = 0; i3 < e3.length; i3 += 2) t2.push(je(e3[i3 + 1], e3[i3]));
+    else for (let i3 = 0; i3 < e3.length; i3 += 2) t2.push(je(e3[i3], e3[i3 + 1]));
+    return m(String.fromCodePoint(...t2));
+  }
+  function je(e3, t2) {
+    return e3 << 8 | t2;
+  }
+  Ee.set(41992, Ne), Ee.set(41993, Ne), Ee.set(41994, Ne), U(N, ["ifd0", "ifd1"], [[50827, function(e3) {
+    return "string" != typeof e3 ? b(e3) : e3;
+  }], [306, ze], [40091, He], [40092, He], [40093, He], [40094, He], [40095, He]]), U(N, "exif", [[40960, Ve], [36864, Ve], [36867, ze], [36868, ze], [40962, Ge], [40963, Ge]]), U(N, "gps", [[0, (e3) => Array.from(e3).join(".")], [7, (e3) => Array.from(e3).join(":")]]);
+  var We = class extends re2 {
+    static canHandle(e3, t2) {
+      return 225 === e3.getUint8(t2 + 1) && 1752462448 === e3.getUint32(t2 + 4) && "http://ns.adobe.com/" === e3.getString(t2 + 4, "http://ns.adobe.com/".length);
+    }
+    static headerLength(e3, t2) {
+      return "http://ns.adobe.com/xmp/extension/" === e3.getString(t2 + 4, "http://ns.adobe.com/xmp/extension/".length) ? 79 : 4 + "http://ns.adobe.com/xap/1.0/".length + 1;
+    }
+    static findPosition(e3, t2) {
+      let i3 = super.findPosition(e3, t2);
+      return i3.multiSegment = i3.extended = 79 === i3.headerLength, i3.multiSegment ? (i3.chunkCount = e3.getUint8(t2 + 72), i3.chunkNumber = e3.getUint8(t2 + 76), 0 !== e3.getUint8(t2 + 77) && i3.chunkNumber++) : (i3.chunkCount = 1 / 0, i3.chunkNumber = -1), i3;
+    }
+    static handleMultiSegments(e3) {
+      return e3.map((e4) => e4.chunk.getString()).join("");
+    }
+    normalizeInput(e3) {
+      return "string" == typeof e3 ? e3 : I.from(e3).getString();
+    }
+    parse(e3 = this.chunk) {
+      if (!this.localOptions.parse) return e3;
+      e3 = function(e4) {
+        let t3 = {}, i4 = {};
+        for (let e6 of Ze) t3[e6] = [], i4[e6] = 0;
+        return e4.replace(et, (e6, n4, s2) => {
+          if ("<" === n4) {
+            let n5 = ++i4[s2];
+            return t3[s2].push(n5), "".concat(e6, "#").concat(n5);
+          }
+          return "".concat(e6, "#").concat(t3[s2].pop());
         });
-        if (selected.length) {
-          entity = context.entity(selected[0]);
-        }
-      }
-      var singular = selected.length === 1 ? selected[0] : null;
-      selection2.html("");
-      if (singular) {
-        selection2.append("h4").attr("class", "history-heading").html(singular);
-      } else {
-        selection2.append("h4").attr("class", "history-heading").call(_t.append("info_panels.selected", { n: selected.length }));
+      }(e3);
+      let t2 = Xe.findAll(e3, "rdf", "Description");
+      0 === t2.length && t2.push(new Xe("rdf", "Description", void 0, e3));
+      let i3, n3 = {};
+      for (let e4 of t2) for (let t3 of e4.properties) i3 = Je(t3.ns, n3), _e(t3, i3);
+      return function(e4) {
+        let t3;
+        for (let i4 in e4) t3 = e4[i4] = f(e4[i4]), void 0 === t3 && delete e4[i4];
+        return f(e4);
+      }(n3);
+    }
+    assignToOutput(e3, t2) {
+      if (this.localOptions.parse) for (let [i3, n3] of Object.entries(t2)) switch (i3) {
+        case "tiff":
+          this.assignObjectToOutput(e3, "ifd0", n3);
+          break;
+        case "exif":
+          this.assignObjectToOutput(e3, "exif", n3);
+          break;
+        case "xmlns":
+          break;
+        default:
+          this.assignObjectToOutput(e3, i3, n3);
       }
-      if (!singular)
-        return;
-      if (entity) {
-        selection2.call(redrawEntity, entity);
-      } else if (note) {
-        selection2.call(redrawNote, note);
+      else e3.xmp = t2;
+    }
+  };
+  c(We, "type", "xmp"), c(We, "multiSegment", true), T.set("xmp", We);
+  var Ke = class _Ke {
+    static findAll(e3) {
+      return qe(e3, /([a-zA-Z0-9-]+):([a-zA-Z0-9-]+)=("[^"]*"|'[^']*')/gm).map(_Ke.unpackMatch);
+    }
+    static unpackMatch(e3) {
+      let t2 = e3[1], i3 = e3[2], n3 = e3[3].slice(1, -1);
+      return n3 = Qe(n3), new _Ke(t2, i3, n3);
+    }
+    constructor(e3, t2, i3) {
+      this.ns = e3, this.name = t2, this.value = i3;
+    }
+    serialize() {
+      return this.value;
+    }
+  };
+  var Xe = class _Xe {
+    static findAll(e3, t2, i3) {
+      if (void 0 !== t2 || void 0 !== i3) {
+        t2 = t2 || "[\\w\\d-]+", i3 = i3 || "[\\w\\d-]+";
+        var n3 = new RegExp("<(".concat(t2, "):(").concat(i3, ")(#\\d+)?((\\s+?[\\w\\d-:]+=(\"[^\"]*\"|'[^']*'))*\\s*)(\\/>|>([\\s\\S]*?)<\\/\\1:\\2\\3>)"), "gm");
+      } else n3 = /<([\w\d-]+):([\w\d-]+)(#\d+)?((\s+?[\w\d-:]+=("[^"]*"|'[^']*'))*\s*)(\/>|>([\s\S]*?)<\/\1:\2\3>)/gm;
+      return qe(e3, n3).map(_Xe.unpackMatch);
+    }
+    static unpackMatch(e3) {
+      let t2 = e3[1], i3 = e3[2], n3 = e3[4], s2 = e3[8];
+      return new _Xe(t2, i3, n3, s2);
+    }
+    constructor(e3, t2, i3, n3) {
+      this.ns = e3, this.name = t2, this.attrString = i3, this.innerXml = n3, this.attrs = Ke.findAll(i3), this.children = _Xe.findAll(n3), this.value = 0 === this.children.length ? Qe(n3) : void 0, this.properties = [...this.attrs, ...this.children];
+    }
+    get isPrimitive() {
+      return void 0 !== this.value && 0 === this.attrs.length && 0 === this.children.length;
+    }
+    get isListContainer() {
+      return 1 === this.children.length && this.children[0].isList;
+    }
+    get isList() {
+      let { ns: e3, name: t2 } = this;
+      return "rdf" === e3 && ("Seq" === t2 || "Bag" === t2 || "Alt" === t2);
+    }
+    get isListItem() {
+      return "rdf" === this.ns && "li" === this.name;
+    }
+    serialize() {
+      if (0 === this.properties.length && void 0 === this.value) return;
+      if (this.isPrimitive) return this.value;
+      if (this.isListContainer) return this.children[0].serialize();
+      if (this.isList) return $e(this.children.map(Ye));
+      if (this.isListItem && 1 === this.children.length && 0 === this.attrs.length) return this.children[0].serialize();
+      let e3 = {};
+      for (let t2 of this.properties) _e(t2, e3);
+      return void 0 !== this.value && (e3.value = this.value), f(e3);
+    }
+  };
+  function _e(e3, t2) {
+    let i3 = e3.serialize();
+    void 0 !== i3 && (t2[e3.name] = i3);
+  }
+  var Ye = (e3) => e3.serialize();
+  var $e = (e3) => 1 === e3.length ? e3[0] : e3;
+  var Je = (e3, t2) => t2[e3] ? t2[e3] : t2[e3] = {};
+  function qe(e3, t2) {
+    let i3, n3 = [];
+    if (!e3) return n3;
+    for (; null !== (i3 = t2.exec(e3)); ) n3.push(i3);
+    return n3;
+  }
+  function Qe(e3) {
+    if (function(e4) {
+      return null == e4 || "null" === e4 || "undefined" === e4 || "" === e4 || "" === e4.trim();
+    }(e3)) return;
+    let t2 = Number(e3);
+    if (!Number.isNaN(t2)) return t2;
+    let i3 = e3.toLowerCase();
+    return "true" === i3 || "false" !== i3 && e3.trim();
+  }
+  var Ze = ["rdf:li", "rdf:Seq", "rdf:Bag", "rdf:Alt", "rdf:Description"];
+  var et = new RegExp("(<|\\/)(".concat(Ze.join("|"), ")"), "g");
+  var tt = Object.freeze({ __proto__: null, default: Me, Exifr: te, fileParsers: w, segmentParsers: T, fileReaders: A, tagKeys: E, tagValues: B, tagRevivers: N, createDictionary: U, extendDictionary: F, fetchUrlAsArrayBuffer: M, readBlobAsArrayBuffer: R, chunkedProps: G, otherSegments: V, segments: z, tiffBlocks: H, segmentsAndBlocks: j, tiffExtractables: W, inheritables: K, allFormatters: X, Options: q, parse: ie, gpsOnlyOptions: me, gps: Se, thumbnailOnlyOptions: Ce, thumbnail: ye, thumbnailUrl: be, orientationOnlyOptions: Ie, orientation: Pe, rotations: ke, get rotateCanvas() {
+    return we;
+  }, get rotateCss() {
+    return Te;
+  }, rotation: Ae });
+  var at = l("fs", (e3) => e3.promises);
+  A.set("fs", class extends ve {
+    async readWhole() {
+      this.chunked = false, this.fs = await at;
+      let e3 = await this.fs.readFile(this.input);
+      this._swapBuffer(e3);
+    }
+    async readChunked() {
+      this.chunked = true, this.fs = await at, await this.open(), await this.readChunk(0, this.options.firstChunkSize);
+    }
+    async open() {
+      void 0 === this.fh && (this.fh = await this.fs.open(this.input, "r"), this.size = (await this.fh.stat(this.input)).size);
+    }
+    async _readChunk(e3, t2) {
+      void 0 === this.fh && await this.open(), e3 + t2 > this.size && (t2 = this.size - e3);
+      var i3 = this.subarray(e3, t2, true);
+      return await this.fh.read(i3.dataView, 0, t2, e3), i3;
+    }
+    async close() {
+      if (this.fh) {
+        let e3 = this.fh;
+        this.fh = void 0, await e3.close();
       }
     }
-    function redrawNote(selection2, note) {
-      if (!note || note.isNew()) {
-        selection2.append("div").call(_t.append("info_panels.history.note_no_history"));
-        return;
+  });
+  A.set("base64", class extends ve {
+    constructor(...e3) {
+      super(...e3), this.input = this.input.replace(/^data:([^;]+);base64,/gim, ""), this.size = this.input.length / 4 * 3, this.input.endsWith("==") ? this.size -= 2 : this.input.endsWith("=") && (this.size -= 1);
+    }
+    async _readChunk(e3, t2) {
+      let i3, n3, r2 = this.input;
+      void 0 === e3 ? (e3 = 0, i3 = 0, n3 = 0) : (i3 = 4 * Math.floor(e3 / 3), n3 = e3 - i3 / 4 * 3), void 0 === t2 && (t2 = this.size);
+      let o2 = e3 + t2, l2 = i3 + 4 * Math.ceil(o2 / 3);
+      r2 = r2.slice(i3, l2);
+      let h2 = Math.min(t2, this.size - e3);
+      if (a) {
+        let t3 = s.from(r2, "base64").slice(n3, n3 + h2);
+        return this.set(t3, e3, true);
       }
-      var list = selection2.append("ul");
-      list.append("li").call(_t.append("info_panels.history.note_comments", { suffix: ":" })).append("span").text(note.comments.length);
-      if (note.comments.length) {
-        list.append("li").call(_t.append("info_panels.history.note_created_date", { suffix: ":" })).append("span").text(displayTimestamp(note.comments[0].date));
-        list.append("li").call(_t.append("info_panels.history.note_created_user", { suffix: ":" })).call(displayUser, note.comments[0].user);
+      {
+        let t3 = this.subarray(e3, h2, true), i4 = atob(r2), s2 = t3.toUint8();
+        for (let e4 = 0; e4 < h2; e4++) s2[e4] = i4.charCodeAt(n3 + e4);
+        return t3;
       }
-      if (osm) {
-        selection2.append("a").attr("class", "view-history-on-osm").attr("target", "_blank").attr("href", osm.noteURL(note)).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("info_panels.history.note_link_text"));
+    }
+  });
+  var ot = class extends se {
+    static canHandle(e3, t2) {
+      return 18761 === t2 || 19789 === t2;
+    }
+    extendOptions(e3) {
+      let { ifd0: t2, xmp: i3, iptc: n3, icc: s2 } = e3;
+      i3.enabled && t2.deps.add(700), n3.enabled && t2.deps.add(33723), s2.enabled && t2.deps.add(34675), t2.finalizeFilters();
+    }
+    async parse() {
+      let { tiff: e3, xmp: t2, iptc: i3, icc: n3 } = this.options;
+      if (e3.enabled || t2.enabled || i3.enabled || n3.enabled) {
+        let e4 = Math.max(S(this.options), this.options.chunkSize);
+        await this.file.ensureChunk(0, e4), this.createParser("tiff", this.file), this.parsers.tiff.parseHeader(), await this.parsers.tiff.parseIfd0Block(), this.adaptTiffPropAsSegment("xmp"), this.adaptTiffPropAsSegment("iptc"), this.adaptTiffPropAsSegment("icc");
       }
     }
-    function redrawEntity(selection2, entity) {
-      if (!entity || entity.isNew()) {
-        selection2.append("div").call(_t.append("info_panels.history.no_history"));
-        return;
+    adaptTiffPropAsSegment(e3) {
+      if (this.parsers.tiff[e3]) {
+        let t2 = this.parsers.tiff[e3];
+        this.injectSegment(e3, t2);
       }
-      var links = selection2.append("div").attr("class", "links");
-      if (osm) {
-        links.append("a").attr("class", "view-history-on-osm").attr("href", osm.historyURL(entity)).attr("target", "_blank").call(_t.append("info_panels.history.history_link"));
+    }
+  };
+  c(ot, "type", "tiff"), w.set("tiff", ot);
+  var lt = l("zlib");
+  var ht = ["ihdr", "iccp", "text", "itxt", "exif"];
+  var ut = class extends se {
+    constructor(...e3) {
+      super(...e3), c(this, "catchError", (e4) => this.errors.push(e4)), c(this, "metaChunks", []), c(this, "unknownChunks", []);
+    }
+    static canHandle(e3, t2) {
+      return 35152 === t2 && 2303741511 === e3.getUint32(0) && 218765834 === e3.getUint32(4);
+    }
+    async parse() {
+      let { file: e3 } = this;
+      await this.findPngChunksInRange("\x89PNG\r\n\1a\n".length, e3.byteLength), await this.readSegments(this.metaChunks), this.findIhdr(), this.parseTextChunks(), await this.findExif().catch(this.catchError), await this.findXmp().catch(this.catchError), await this.findIcc().catch(this.catchError);
+    }
+    async findPngChunksInRange(e3, t2) {
+      let { file: i3 } = this;
+      for (; e3 < t2; ) {
+        let t3 = i3.getUint32(e3), n3 = i3.getUint32(e3 + 4), s2 = i3.getString(e3 + 4, 4).toLowerCase(), r2 = t3 + 4 + 4 + 4, a2 = { type: s2, offset: e3, length: r2, start: e3 + 4 + 4, size: t3, marker: n3 };
+        ht.includes(s2) ? this.metaChunks.push(a2) : this.unknownChunks.push(a2), e3 += r2;
       }
-      links.append("a").attr("class", "pewu-history-viewer-link").attr("href", "https://pewu.github.io/osm-history/#/" + entity.type + "/" + entity.osmId()).attr("target", "_blank").attr("tabindex", -1).text("PeWu");
-      var list = selection2.append("ul");
-      list.append("li").call(_t.append("info_panels.history.version", { suffix: ":" })).append("span").text(entity.version);
-      list.append("li").call(_t.append("info_panels.history.last_edit", { suffix: ":" })).append("span").text(displayTimestamp(entity.timestamp));
-      list.append("li").call(_t.append("info_panels.history.edited_by", { suffix: ":" })).call(displayUser, entity.user);
-      list.append("li").call(_t.append("info_panels.history.changeset", { suffix: ":" })).call(displayChangeset, entity.changeset);
     }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.map().on("drawn.info-history", function() {
-        selection2.call(redraw);
-      });
-      context.on("enter.info-history", function() {
-        selection2.call(redraw);
-      });
-    };
-    panel.off = function() {
-      context.map().on("drawn.info-history", null);
-      context.on("enter.info-history", null);
-    };
-    panel.id = "history";
-    panel.label = _t.append("info_panels.history.title");
-    panel.key = _t("info_panels.history.key");
-    return panel;
-  }
-
-  // modules/util/units.js
-  var OSM_PRECISION = 7;
-  function displayLength(m, isImperial) {
-    var d = m * (isImperial ? 3.28084 : 1);
-    var unit2;
-    if (isImperial) {
-      if (d >= 5280) {
-        d /= 5280;
-        unit2 = "miles";
-      } else {
-        unit2 = "feet";
+    parseTextChunks() {
+      let e3 = this.metaChunks.filter((e4) => "text" === e4.type);
+      for (let t2 of e3) {
+        let [e4, i3] = this.file.getString(t2.start, t2.size).split("\0");
+        this.injectKeyValToIhdr(e4, i3);
       }
-    } else {
-      if (d >= 1e3) {
-        d /= 1e3;
-        unit2 = "kilometers";
-      } else {
-        unit2 = "meters";
+    }
+    injectKeyValToIhdr(e3, t2) {
+      let i3 = this.parsers.ihdr;
+      i3 && i3.raw.set(e3, t2);
+    }
+    findIhdr() {
+      let e3 = this.metaChunks.find((e4) => "ihdr" === e4.type);
+      e3 && false !== this.options.ihdr.enabled && this.createParser("ihdr", e3.chunk);
+    }
+    async findExif() {
+      let e3 = this.metaChunks.find((e4) => "exif" === e4.type);
+      e3 && this.injectSegment("tiff", e3.chunk);
+    }
+    async findXmp() {
+      let e3 = this.metaChunks.filter((e4) => "itxt" === e4.type);
+      for (let t2 of e3) {
+        "XML:com.adobe.xmp" === t2.chunk.getString(0, "XML:com.adobe.xmp".length) && this.injectSegment("xmp", t2.chunk);
       }
     }
-    return _t("units." + unit2, {
-      quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
-        maximumSignificantDigits: 4
-      })
-    });
-  }
-  function displayArea(m2, isImperial) {
-    var locale2 = _mainLocalizer.localeCode();
-    var d = m2 * (isImperial ? 10.7639111056 : 1);
-    var d1, d2, area;
-    var unit1 = "";
-    var unit2 = "";
-    if (isImperial) {
-      if (d >= 6969600) {
-        d1 = d / 27878400;
-        unit1 = "square_miles";
-      } else {
-        d1 = d;
-        unit1 = "square_feet";
+    async findIcc() {
+      let e3 = this.metaChunks.find((e4) => "iccp" === e4.type);
+      if (!e3) return;
+      let { chunk: t2 } = e3, i3 = t2.getUint8Array(0, 81), s2 = 0;
+      for (; s2 < 80 && 0 !== i3[s2]; ) s2++;
+      let r2 = s2 + 2, a2 = t2.getString(0, s2);
+      if (this.injectKeyValToIhdr("ProfileName", a2), n2) {
+        let e4 = await lt, i4 = t2.getUint8Array(r2);
+        i4 = e4.inflateSync(i4), this.injectSegment("icc", i4);
       }
-      if (d > 4356 && d < 4356e4) {
-        d2 = d / 43560;
-        unit2 = "acres";
+    }
+  };
+  c(ut, "type", "png"), w.set("png", ut), U(E, "interop", [[1, "InteropIndex"], [2, "InteropVersion"], [4096, "RelatedImageFileFormat"], [4097, "RelatedImageWidth"], [4098, "RelatedImageHeight"]]), F(E, "ifd0", [[11, "ProcessingSoftware"], [254, "SubfileType"], [255, "OldSubfileType"], [263, "Thresholding"], [264, "CellWidth"], [265, "CellLength"], [266, "FillOrder"], [269, "DocumentName"], [280, "MinSampleValue"], [281, "MaxSampleValue"], [285, "PageName"], [286, "XPosition"], [287, "YPosition"], [290, "GrayResponseUnit"], [297, "PageNumber"], [321, "HalftoneHints"], [322, "TileWidth"], [323, "TileLength"], [332, "InkSet"], [337, "TargetPrinter"], [18246, "Rating"], [18249, "RatingPercent"], [33550, "PixelScale"], [34264, "ModelTransform"], [34377, "PhotoshopSettings"], [50706, "DNGVersion"], [50707, "DNGBackwardVersion"], [50708, "UniqueCameraModel"], [50709, "LocalizedCameraModel"], [50736, "DNGLensInfo"], [50739, "ShadowScale"], [50740, "DNGPrivateData"], [33920, "IntergraphMatrix"], [33922, "ModelTiePoint"], [34118, "SEMInfo"], [34735, "GeoTiffDirectory"], [34736, "GeoTiffDoubleParams"], [34737, "GeoTiffAsciiParams"], [50341, "PrintIM"], [50721, "ColorMatrix1"], [50722, "ColorMatrix2"], [50723, "CameraCalibration1"], [50724, "CameraCalibration2"], [50725, "ReductionMatrix1"], [50726, "ReductionMatrix2"], [50727, "AnalogBalance"], [50728, "AsShotNeutral"], [50729, "AsShotWhiteXY"], [50730, "BaselineExposure"], [50731, "BaselineNoise"], [50732, "BaselineSharpness"], [50734, "LinearResponseLimit"], [50735, "CameraSerialNumber"], [50741, "MakerNoteSafety"], [50778, "CalibrationIlluminant1"], [50779, "CalibrationIlluminant2"], [50781, "RawDataUniqueID"], [50827, "OriginalRawFileName"], [50828, "OriginalRawFileData"], [50831, "AsShotICCProfile"], [50832, "AsShotPreProfileMatrix"], [50833, "CurrentICCProfile"], [50834, "CurrentPreProfileMatrix"], [50879, "ColorimetricReference"], [50885, "SRawType"], [50898, "PanasonicTitle"], [50899, "PanasonicTitle2"], [50931, "CameraCalibrationSig"], [50932, "ProfileCalibrationSig"], [50933, "ProfileIFD"], [50934, "AsShotProfileName"], [50936, "ProfileName"], [50937, "ProfileHueSatMapDims"], [50938, "ProfileHueSatMapData1"], [50939, "ProfileHueSatMapData2"], [50940, "ProfileToneCurve"], [50941, "ProfileEmbedPolicy"], [50942, "ProfileCopyright"], [50964, "ForwardMatrix1"], [50965, "ForwardMatrix2"], [50966, "PreviewApplicationName"], [50967, "PreviewApplicationVersion"], [50968, "PreviewSettingsName"], [50969, "PreviewSettingsDigest"], [50970, "PreviewColorSpace"], [50971, "PreviewDateTime"], [50972, "RawImageDigest"], [50973, "OriginalRawFileDigest"], [50981, "ProfileLookTableDims"], [50982, "ProfileLookTableData"], [51043, "TimeCodes"], [51044, "FrameRate"], [51058, "TStop"], [51081, "ReelName"], [51089, "OriginalDefaultFinalSize"], [51090, "OriginalBestQualitySize"], [51091, "OriginalDefaultCropSize"], [51105, "CameraLabel"], [51107, "ProfileHueSatMapEncoding"], [51108, "ProfileLookTableEncoding"], [51109, "BaselineExposureOffset"], [51110, "DefaultBlackRender"], [51111, "NewRawImageDigest"], [51112, "RawToPreviewGain"]]);
+  var ct = [[273, "StripOffsets"], [279, "StripByteCounts"], [288, "FreeOffsets"], [289, "FreeByteCounts"], [291, "GrayResponseCurve"], [292, "T4Options"], [293, "T6Options"], [300, "ColorResponseUnit"], [320, "ColorMap"], [324, "TileOffsets"], [325, "TileByteCounts"], [326, "BadFaxLines"], [327, "CleanFaxData"], [328, "ConsecutiveBadFaxLines"], [330, "SubIFD"], [333, "InkNames"], [334, "NumberofInks"], [336, "DotRange"], [338, "ExtraSamples"], [339, "SampleFormat"], [340, "SMinSampleValue"], [341, "SMaxSampleValue"], [342, "TransferRange"], [343, "ClipPath"], [344, "XClipPathUnits"], [345, "YClipPathUnits"], [346, "Indexed"], [347, "JPEGTables"], [351, "OPIProxy"], [400, "GlobalParametersIFD"], [401, "ProfileType"], [402, "FaxProfile"], [403, "CodingMethods"], [404, "VersionYear"], [405, "ModeNumber"], [433, "Decode"], [434, "DefaultImageColor"], [435, "T82Options"], [437, "JPEGTables"], [512, "JPEGProc"], [515, "JPEGRestartInterval"], [517, "JPEGLosslessPredictors"], [518, "JPEGPointTransforms"], [519, "JPEGQTables"], [520, "JPEGDCTables"], [521, "JPEGACTables"], [559, "StripRowCounts"], [999, "USPTOMiscellaneous"], [18247, "XP_DIP_XML"], [18248, "StitchInfo"], [28672, "SonyRawFileType"], [28688, "SonyToneCurve"], [28721, "VignettingCorrection"], [28722, "VignettingCorrParams"], [28724, "ChromaticAberrationCorrection"], [28725, "ChromaticAberrationCorrParams"], [28726, "DistortionCorrection"], [28727, "DistortionCorrParams"], [29895, "SonyCropTopLeft"], [29896, "SonyCropSize"], [32781, "ImageID"], [32931, "WangTag1"], [32932, "WangAnnotation"], [32933, "WangTag3"], [32934, "WangTag4"], [32953, "ImageReferencePoints"], [32954, "RegionXformTackPoint"], [32955, "WarpQuadrilateral"], [32956, "AffineTransformMat"], [32995, "Matteing"], [32996, "DataType"], [32997, "ImageDepth"], [32998, "TileDepth"], [33300, "ImageFullWidth"], [33301, "ImageFullHeight"], [33302, "TextureFormat"], [33303, "WrapModes"], [33304, "FovCot"], [33305, "MatrixWorldToScreen"], [33306, "MatrixWorldToCamera"], [33405, "Model2"], [33421, "CFARepeatPatternDim"], [33422, "CFAPattern2"], [33423, "BatteryLevel"], [33424, "KodakIFD"], [33445, "MDFileTag"], [33446, "MDScalePixel"], [33447, "MDColorTable"], [33448, "MDLabName"], [33449, "MDSampleInfo"], [33450, "MDPrepDate"], [33451, "MDPrepTime"], [33452, "MDFileUnits"], [33589, "AdventScale"], [33590, "AdventRevision"], [33628, "UIC1Tag"], [33629, "UIC2Tag"], [33630, "UIC3Tag"], [33631, "UIC4Tag"], [33918, "IntergraphPacketData"], [33919, "IntergraphFlagRegisters"], [33921, "INGRReserved"], [34016, "Site"], [34017, "ColorSequence"], [34018, "IT8Header"], [34019, "RasterPadding"], [34020, "BitsPerRunLength"], [34021, "BitsPerExtendedRunLength"], [34022, "ColorTable"], [34023, "ImageColorIndicator"], [34024, "BackgroundColorIndicator"], [34025, "ImageColorValue"], [34026, "BackgroundColorValue"], [34027, "PixelIntensityRange"], [34028, "TransparencyIndicator"], [34029, "ColorCharacterization"], [34030, "HCUsage"], [34031, "TrapIndicator"], [34032, "CMYKEquivalent"], [34152, "AFCP_IPTC"], [34232, "PixelMagicJBIGOptions"], [34263, "JPLCartoIFD"], [34306, "WB_GRGBLevels"], [34310, "LeafData"], [34687, "TIFF_FXExtensions"], [34688, "MultiProfiles"], [34689, "SharedData"], [34690, "T88Options"], [34732, "ImageLayer"], [34750, "JBIGOptions"], [34856, "Opto-ElectricConvFactor"], [34857, "Interlace"], [34908, "FaxRecvParams"], [34909, "FaxSubAddress"], [34910, "FaxRecvTime"], [34929, "FedexEDR"], [34954, "LeafSubIFD"], [37387, "FlashEnergy"], [37388, "SpatialFrequencyResponse"], [37389, "Noise"], [37390, "FocalPlaneXResolution"], [37391, "FocalPlaneYResolution"], [37392, "FocalPlaneResolutionUnit"], [37397, "ExposureIndex"], [37398, "TIFF-EPStandardID"], [37399, "SensingMethod"], [37434, "CIP3DataFile"], [37435, "CIP3Sheet"], [37436, "CIP3Side"], [37439, "StoNits"], [37679, "MSDocumentText"], [37680, "MSPropertySetStorage"], [37681, "MSDocumentTextPosition"], [37724, "ImageSourceData"], [40965, "InteropIFD"], [40976, "SamsungRawPointersOffset"], [40977, "SamsungRawPointersLength"], [41217, "SamsungRawByteOrder"], [41218, "SamsungRawUnknown"], [41484, "SpatialFrequencyResponse"], [41485, "Noise"], [41489, "ImageNumber"], [41490, "SecurityClassification"], [41491, "ImageHistory"], [41494, "TIFF-EPStandardID"], [41995, "DeviceSettingDescription"], [42112, "GDALMetadata"], [42113, "GDALNoData"], [44992, "ExpandSoftware"], [44993, "ExpandLens"], [44994, "ExpandFilm"], [44995, "ExpandFilterLens"], [44996, "ExpandScanner"], [44997, "ExpandFlashLamp"], [46275, "HasselbladRawImage"], [48129, "PixelFormat"], [48130, "Transformation"], [48131, "Uncompressed"], [48132, "ImageType"], [48256, "ImageWidth"], [48257, "ImageHeight"], [48258, "WidthResolution"], [48259, "HeightResolution"], [48320, "ImageOffset"], [48321, "ImageByteCount"], [48322, "AlphaOffset"], [48323, "AlphaByteCount"], [48324, "ImageDataDiscard"], [48325, "AlphaDataDiscard"], [50215, "OceScanjobDesc"], [50216, "OceApplicationSelector"], [50217, "OceIDNumber"], [50218, "OceImageLogic"], [50255, "Annotations"], [50459, "HasselbladExif"], [50547, "OriginalFileName"], [50560, "USPTOOriginalContentType"], [50656, "CR2CFAPattern"], [50710, "CFAPlaneColor"], [50711, "CFALayout"], [50712, "LinearizationTable"], [50713, "BlackLevelRepeatDim"], [50714, "BlackLevel"], [50715, "BlackLevelDeltaH"], [50716, "BlackLevelDeltaV"], [50717, "WhiteLevel"], [50718, "DefaultScale"], [50719, "DefaultCropOrigin"], [50720, "DefaultCropSize"], [50733, "BayerGreenSplit"], [50737, "ChromaBlurRadius"], [50738, "AntiAliasStrength"], [50752, "RawImageSegmentation"], [50780, "BestQualityScale"], [50784, "AliasLayerMetadata"], [50829, "ActiveArea"], [50830, "MaskedAreas"], [50935, "NoiseReductionApplied"], [50974, "SubTileBlockSize"], [50975, "RowInterleaveFactor"], [51008, "OpcodeList1"], [51009, "OpcodeList2"], [51022, "OpcodeList3"], [51041, "NoiseProfile"], [51114, "CacheVersion"], [51125, "DefaultUserCrop"], [51157, "NikonNEFInfo"], [65024, "KdcIFD"]];
+  F(E, "ifd0", ct), F(E, "exif", ct), U(B, "gps", [[23, { M: "Magnetic North", T: "True North" }], [25, { K: "Kilometers", M: "Miles", N: "Nautical Miles" }]]);
+  var ft = class extends re2 {
+    static canHandle(e3, t2) {
+      return 224 === e3.getUint8(t2 + 1) && 1246120262 === e3.getUint32(t2 + 4) && 0 === e3.getUint8(t2 + 8);
+    }
+    parse() {
+      return this.parseTags(), this.translate(), this.output;
+    }
+    parseTags() {
+      this.raw = /* @__PURE__ */ new Map([[0, this.chunk.getUint16(0)], [2, this.chunk.getUint8(2)], [3, this.chunk.getUint16(3)], [5, this.chunk.getUint16(5)], [7, this.chunk.getUint8(7)], [8, this.chunk.getUint8(8)]]);
+    }
+  };
+  c(ft, "type", "jfif"), c(ft, "headerLength", 9), T.set("jfif", ft), U(E, "jfif", [[0, "JFIFVersion"], [2, "ResolutionUnit"], [3, "XResolution"], [5, "YResolution"], [7, "ThumbnailWidth"], [8, "ThumbnailHeight"]]);
+  var dt = class extends re2 {
+    parse() {
+      return this.parseTags(), this.translate(), this.output;
+    }
+    parseTags() {
+      this.raw = new Map([[0, this.chunk.getUint32(0)], [4, this.chunk.getUint32(4)], [8, this.chunk.getUint8(8)], [9, this.chunk.getUint8(9)], [10, this.chunk.getUint8(10)], [11, this.chunk.getUint8(11)], [12, this.chunk.getUint8(12)], ...Array.from(this.raw)]);
+    }
+  };
+  c(dt, "type", "ihdr"), T.set("ihdr", dt), U(E, "ihdr", [[0, "ImageWidth"], [4, "ImageHeight"], [8, "BitDepth"], [9, "ColorType"], [10, "Compression"], [11, "Filter"], [12, "Interlace"]]), U(B, "ihdr", [[9, { 0: "Grayscale", 2: "RGB", 3: "Palette", 4: "Grayscale with Alpha", 6: "RGB with Alpha", DEFAULT: "Unknown" }], [10, { 0: "Deflate/Inflate", DEFAULT: "Unknown" }], [11, { 0: "Adaptive", DEFAULT: "Unknown" }], [12, { 0: "Noninterlaced", 1: "Adam7 Interlace", DEFAULT: "Unknown" }]]);
+  var pt = class extends re2 {
+    static canHandle(e3, t2) {
+      return 226 === e3.getUint8(t2 + 1) && 1229144927 === e3.getUint32(t2 + 4);
+    }
+    static findPosition(e3, t2) {
+      let i3 = super.findPosition(e3, t2);
+      return i3.chunkNumber = e3.getUint8(t2 + 16), i3.chunkCount = e3.getUint8(t2 + 17), i3.multiSegment = i3.chunkCount > 1, i3;
+    }
+    static handleMultiSegments(e3) {
+      return function(e4) {
+        let t2 = function(e6) {
+          let t3 = e6[0].constructor, i3 = 0;
+          for (let t4 of e6) i3 += t4.length;
+          let n3 = new t3(i3), s2 = 0;
+          for (let t4 of e6) n3.set(t4, s2), s2 += t4.length;
+          return n3;
+        }(e4.map((e6) => e6.chunk.toUint8()));
+        return new I(t2);
+      }(e3);
+    }
+    parse() {
+      return this.raw = /* @__PURE__ */ new Map(), this.parseHeader(), this.parseTags(), this.translate(), this.output;
+    }
+    parseHeader() {
+      let { raw: e3 } = this;
+      this.chunk.byteLength < 84 && g2("ICC header is too short");
+      for (let [t2, i3] of Object.entries(gt)) {
+        t2 = parseInt(t2, 10);
+        let n3 = i3(this.chunk, t2);
+        "\0\0\0\0" !== n3 && e3.set(t2, n3);
       }
-    } else {
-      if (d >= 25e4) {
-        d1 = d / 1e6;
-        unit1 = "square_kilometers";
-      } else {
-        d1 = d;
-        unit1 = "square_meters";
+    }
+    parseTags() {
+      let e3, t2, i3, n3, s2, { raw: r2 } = this, a2 = this.chunk.getUint32(128), o2 = 132, l2 = this.chunk.byteLength;
+      for (; a2--; ) {
+        if (e3 = this.chunk.getString(o2, 4), t2 = this.chunk.getUint32(o2 + 4), i3 = this.chunk.getUint32(o2 + 8), n3 = this.chunk.getString(t2, 4), t2 + i3 > l2) return void console.warn("reached the end of the first ICC chunk. Enable options.tiff.multiSegment to read all ICC segments.");
+        s2 = this.parseTag(n3, t2, i3), void 0 !== s2 && "\0\0\0\0" !== s2 && r2.set(e3, s2), o2 += 12;
       }
-      if (d > 1e3 && d < 1e7) {
-        d2 = d / 1e4;
-        unit2 = "hectares";
+    }
+    parseTag(e3, t2, i3) {
+      switch (e3) {
+        case "desc":
+          return this.parseDesc(t2);
+        case "mluc":
+          return this.parseMluc(t2);
+        case "text":
+          return this.parseText(t2, i3);
+        case "sig ":
+          return this.parseSig(t2);
       }
+      if (!(t2 + i3 > this.chunk.byteLength)) return this.chunk.getUint8Array(t2, i3);
     }
-    area = _t("units." + unit1, {
-      quantity: d1.toLocaleString(locale2, {
-        maximumSignificantDigits: 4
-      })
+    parseDesc(e3) {
+      let t2 = this.chunk.getUint32(e3 + 8) - 1;
+      return m(this.chunk.getString(e3 + 12, t2));
+    }
+    parseText(e3, t2) {
+      return m(this.chunk.getString(e3 + 8, t2 - 8));
+    }
+    parseSig(e3) {
+      return m(this.chunk.getString(e3 + 8, 4));
+    }
+    parseMluc(e3) {
+      let { chunk: t2 } = this, i3 = t2.getUint32(e3 + 8), n3 = t2.getUint32(e3 + 12), s2 = e3 + 16, r2 = [];
+      for (let a2 = 0; a2 < i3; a2++) {
+        let i4 = t2.getString(s2 + 0, 2), a3 = t2.getString(s2 + 2, 2), o2 = t2.getUint32(s2 + 4), l2 = t2.getUint32(s2 + 8) + e3, h2 = m(t2.getUnicodeString(l2, o2));
+        r2.push({ lang: i4, country: a3, text: h2 }), s2 += n3;
+      }
+      return 1 === i3 ? r2[0].text : r2;
+    }
+    translateValue(e3, t2) {
+      return "string" == typeof e3 ? t2[e3] || t2[e3.toLowerCase()] || e3 : t2[e3] || e3;
+    }
+  };
+  c(pt, "type", "icc"), c(pt, "multiSegment", true), c(pt, "headerLength", 18);
+  var gt = { 4: mt, 8: function(e3, t2) {
+    return [e3.getUint8(t2), e3.getUint8(t2 + 1) >> 4, e3.getUint8(t2 + 1) % 16].map((e4) => e4.toString(10)).join(".");
+  }, 12: mt, 16: mt, 20: mt, 24: function(e3, t2) {
+    const i3 = e3.getUint16(t2), n3 = e3.getUint16(t2 + 2) - 1, s2 = e3.getUint16(t2 + 4), r2 = e3.getUint16(t2 + 6), a2 = e3.getUint16(t2 + 8), o2 = e3.getUint16(t2 + 10);
+    return new Date(Date.UTC(i3, n3, s2, r2, a2, o2));
+  }, 36: mt, 40: mt, 48: mt, 52: mt, 64: (e3, t2) => e3.getUint32(t2), 80: mt };
+  function mt(e3, t2) {
+    return m(e3.getString(t2, 4));
+  }
+  T.set("icc", pt), U(E, "icc", [[4, "ProfileCMMType"], [8, "ProfileVersion"], [12, "ProfileClass"], [16, "ColorSpaceData"], [20, "ProfileConnectionSpace"], [24, "ProfileDateTime"], [36, "ProfileFileSignature"], [40, "PrimaryPlatform"], [44, "CMMFlags"], [48, "DeviceManufacturer"], [52, "DeviceModel"], [56, "DeviceAttributes"], [64, "RenderingIntent"], [68, "ConnectionSpaceIlluminant"], [80, "ProfileCreator"], [84, "ProfileID"], ["Header", "ProfileHeader"], ["MS00", "WCSProfiles"], ["bTRC", "BlueTRC"], ["bXYZ", "BlueMatrixColumn"], ["bfd", "UCRBG"], ["bkpt", "MediaBlackPoint"], ["calt", "CalibrationDateTime"], ["chad", "ChromaticAdaptation"], ["chrm", "Chromaticity"], ["ciis", "ColorimetricIntentImageState"], ["clot", "ColorantTableOut"], ["clro", "ColorantOrder"], ["clrt", "ColorantTable"], ["cprt", "ProfileCopyright"], ["crdi", "CRDInfo"], ["desc", "ProfileDescription"], ["devs", "DeviceSettings"], ["dmdd", "DeviceModelDesc"], ["dmnd", "DeviceMfgDesc"], ["dscm", "ProfileDescriptionML"], ["fpce", "FocalPlaneColorimetryEstimates"], ["gTRC", "GreenTRC"], ["gXYZ", "GreenMatrixColumn"], ["gamt", "Gamut"], ["kTRC", "GrayTRC"], ["lumi", "Luminance"], ["meas", "Measurement"], ["meta", "Metadata"], ["mmod", "MakeAndModel"], ["ncl2", "NamedColor2"], ["ncol", "NamedColor"], ["ndin", "NativeDisplayInfo"], ["pre0", "Preview0"], ["pre1", "Preview1"], ["pre2", "Preview2"], ["ps2i", "PS2RenderingIntent"], ["ps2s", "PostScript2CSA"], ["psd0", "PostScript2CRD0"], ["psd1", "PostScript2CRD1"], ["psd2", "PostScript2CRD2"], ["psd3", "PostScript2CRD3"], ["pseq", "ProfileSequenceDesc"], ["psid", "ProfileSequenceIdentifier"], ["psvm", "PS2CRDVMSize"], ["rTRC", "RedTRC"], ["rXYZ", "RedMatrixColumn"], ["resp", "OutputResponse"], ["rhoc", "ReflectionHardcopyOrigColorimetry"], ["rig0", "PerceptualRenderingIntentGamut"], ["rig2", "SaturationRenderingIntentGamut"], ["rpoc", "ReflectionPrintOutputColorimetry"], ["sape", "SceneAppearanceEstimates"], ["scoe", "SceneColorimetryEstimates"], ["scrd", "ScreeningDesc"], ["scrn", "Screening"], ["targ", "CharTarget"], ["tech", "Technology"], ["vcgt", "VideoCardGamma"], ["view", "ViewingConditions"], ["vued", "ViewingCondDesc"], ["wtpt", "MediaWhitePoint"]]);
+  var St = { "4d2p": "Erdt Systems", AAMA: "Aamazing Technologies", ACER: "Acer", ACLT: "Acolyte Color Research", ACTI: "Actix Sytems", ADAR: "Adara Technology", ADBE: "Adobe", ADI: "ADI Systems", AGFA: "Agfa Graphics", ALMD: "Alps Electric", ALPS: "Alps Electric", ALWN: "Alwan Color Expertise", AMTI: "Amiable Technologies", AOC: "AOC International", APAG: "Apago", APPL: "Apple Computer", AST: "AST", "AT&T": "AT&T", BAEL: "BARBIERI electronic", BRCO: "Barco NV", BRKP: "Breakpoint", BROT: "Brother", BULL: "Bull", BUS: "Bus Computer Systems", "C-IT": "C-Itoh", CAMR: "Intel", CANO: "Canon", CARR: "Carroll Touch", CASI: "Casio", CBUS: "Colorbus PL", CEL: "Crossfield", CELx: "Crossfield", CGS: "CGS Publishing Technologies International", CHM: "Rochester Robotics", CIGL: "Colour Imaging Group, London", CITI: "Citizen", CL00: "Candela", CLIQ: "Color IQ", CMCO: "Chromaco", CMiX: "CHROMiX", COLO: "Colorgraphic Communications", COMP: "Compaq", COMp: "Compeq/Focus Technology", CONR: "Conrac Display Products", CORD: "Cordata Technologies", CPQ: "Compaq", CPRO: "ColorPro", CRN: "Cornerstone", CTX: "CTX International", CVIS: "ColorVision", CWC: "Fujitsu Laboratories", DARI: "Darius Technology", DATA: "Dataproducts", DCP: "Dry Creek Photo", DCRC: "Digital Contents Resource Center, Chung-Ang University", DELL: "Dell Computer", DIC: "Dainippon Ink and Chemicals", DICO: "Diconix", DIGI: "Digital", "DL&C": "Digital Light & Color", DPLG: "Doppelganger", DS: "Dainippon Screen", DSOL: "DOOSOL", DUPN: "DuPont", EPSO: "Epson", ESKO: "Esko-Graphics", ETRI: "Electronics and Telecommunications Research Institute", EVER: "Everex Systems", EXAC: "ExactCODE", Eizo: "Eizo", FALC: "Falco Data Products", FF: "Fuji Photo Film", FFEI: "FujiFilm Electronic Imaging", FNRD: "Fnord Software", FORA: "Fora", FORE: "Forefront Technology", FP: "Fujitsu", FPA: "WayTech Development", FUJI: "Fujitsu", FX: "Fuji Xerox", GCC: "GCC Technologies", GGSL: "Global Graphics Software", GMB: "Gretagmacbeth", GMG: "GMG", GOLD: "GoldStar Technology", GOOG: "Google", GPRT: "Giantprint", GTMB: "Gretagmacbeth", GVC: "WayTech Development", GW2K: "Sony", HCI: "HCI", HDM: "Heidelberger Druckmaschinen", HERM: "Hermes", HITA: "Hitachi America", HP: "Hewlett-Packard", HTC: "Hitachi", HiTi: "HiTi Digital", IBM: "IBM", IDNT: "Scitex", IEC: "Hewlett-Packard", IIYA: "Iiyama North America", IKEG: "Ikegami Electronics", IMAG: "Image Systems", IMI: "Ingram Micro", INTC: "Intel", INTL: "N/A (INTL)", INTR: "Intra Electronics", IOCO: "Iocomm International Technology", IPS: "InfoPrint Solutions Company", IRIS: "Scitex", ISL: "Ichikawa Soft Laboratory", ITNL: "N/A (ITNL)", IVM: "IVM", IWAT: "Iwatsu Electric", Idnt: "Scitex", Inca: "Inca Digital Printers", Iris: "Scitex", JPEG: "Joint Photographic Experts Group", JSFT: "Jetsoft Development", JVC: "JVC Information Products", KART: "Scitex", KFC: "KFC Computek Components", KLH: "KLH Computers", KMHD: "Konica Minolta", KNCA: "Konica", KODA: "Kodak", KYOC: "Kyocera", Kart: "Scitex", LCAG: "Leica", LCCD: "Leeds Colour", LDAK: "Left Dakota", LEAD: "Leading Technology", LEXM: "Lexmark International", LINK: "Link Computer", LINO: "Linotronic", LITE: "Lite-On", Leaf: "Leaf", Lino: "Linotronic", MAGC: "Mag Computronic", MAGI: "MAG Innovision", MANN: "Mannesmann", MICN: "Micron Technology", MICR: "Microtek", MICV: "Microvitec", MINO: "Minolta", MITS: "Mitsubishi Electronics America", MITs: "Mitsuba", MNLT: "Minolta", MODG: "Modgraph", MONI: "Monitronix", MONS: "Monaco Systems", MORS: "Morse Technology", MOTI: "Motive Systems", MSFT: "Microsoft", MUTO: "MUTOH INDUSTRIES", Mits: "Mitsubishi Electric", NANA: "NANAO", NEC: "NEC", NEXP: "NexPress Solutions", NISS: "Nissei Sangyo America", NKON: "Nikon", NONE: "none", OCE: "Oce Technologies", OCEC: "OceColor", OKI: "Oki", OKID: "Okidata", OKIP: "Okidata", OLIV: "Olivetti", OLYM: "Olympus", ONYX: "Onyx Graphics", OPTI: "Optiquest", PACK: "Packard Bell", PANA: "Matsushita Electric Industrial", PANT: "Pantone", PBN: "Packard Bell", PFU: "PFU", PHIL: "Philips Consumer Electronics", PNTX: "HOYA", POne: "Phase One A/S", PREM: "Premier Computer Innovations", PRIN: "Princeton Graphic Systems", PRIP: "Princeton Publishing Labs", QLUX: "Hong Kong", QMS: "QMS", QPCD: "QPcard AB", QUAD: "QuadLaser", QUME: "Qume", RADI: "Radius", RDDx: "Integrated Color Solutions", RDG: "Roland DG", REDM: "REDMS Group", RELI: "Relisys", RGMS: "Rolf Gierling Multitools", RICO: "Ricoh", RNLD: "Edmund Ronald", ROYA: "Royal", RPC: "Ricoh Printing Systems", RTL: "Royal Information Electronics", SAMP: "Sampo", SAMS: "Samsung", SANT: "Jaime Santana Pomares", SCIT: "Scitex", SCRN: "Dainippon Screen", SDP: "Scitex", SEC: "Samsung", SEIK: "Seiko Instruments", SEIk: "Seikosha", SGUY: "ScanGuy.com", SHAR: "Sharp Laboratories", SICC: "International Color Consortium", SONY: "Sony", SPCL: "SpectraCal", STAR: "Star", STC: "Sampo Technology", Scit: "Scitex", Sdp: "Scitex", Sony: "Sony", TALO: "Talon Technology", TAND: "Tandy", TATU: "Tatung", TAXA: "TAXAN America", TDS: "Tokyo Denshi Sekei", TECO: "TECO Information Systems", TEGR: "Tegra", TEKT: "Tektronix", TI: "Texas Instruments", TMKR: "TypeMaker", TOSB: "Toshiba", TOSH: "Toshiba", TOTK: "TOTOKU ELECTRIC", TRIU: "Triumph", TSBT: "Toshiba", TTX: "TTX Computer Products", TVM: "TVM Professional Monitor", TW: "TW Casper", ULSX: "Ulead Systems", UNIS: "Unisys", UTZF: "Utz Fehlau & Sohn", VARI: "Varityper", VIEW: "Viewsonic", VISL: "Visual communication", VIVO: "Vivo Mobile Communication", WANG: "Wang", WLBR: "Wilbur Imaging", WTG2: "Ware To Go", WYSE: "WYSE Technology", XERX: "Xerox", XRIT: "X-Rite", ZRAN: "Zoran", Zebr: "Zebra Technologies", appl: "Apple Computer", bICC: "basICColor", berg: "bergdesign", ceyd: "Integrated Color Solutions", clsp: "MacDermid ColorSpan", ds: "Dainippon Screen", dupn: "DuPont", ffei: "FujiFilm Electronic Imaging", flux: "FluxData", iris: "Scitex", kart: "Scitex", lcms: "Little CMS", lino: "Linotronic", none: "none", ob4d: "Erdt Systems", obic: "Medigraph", quby: "Qubyx Sarl", scit: "Scitex", scrn: "Dainippon Screen", sdp: "Scitex", siwi: "SIWI GRAFIKA", yxym: "YxyMaster" };
+  var Ct = { scnr: "Scanner", mntr: "Monitor", prtr: "Printer", link: "Device Link", abst: "Abstract", spac: "Color Space Conversion Profile", nmcl: "Named Color", cenc: "ColorEncodingSpace profile", mid: "MultiplexIdentification profile", mlnk: "MultiplexLink profile", mvis: "MultiplexVisualization profile", nkpf: "Nikon Input Device Profile (NON-STANDARD!)" };
+  U(B, "icc", [[4, St], [12, Ct], [40, Object.assign({}, St, Ct)], [48, St], [80, St], [64, { 0: "Perceptual", 1: "Relative Colorimetric", 2: "Saturation", 3: "Absolute Colorimetric" }], ["tech", { amd: "Active Matrix Display", crt: "Cathode Ray Tube Display", kpcd: "Photo CD", pmd: "Passive Matrix Display", dcam: "Digital Camera", dcpj: "Digital Cinema Projector", dmpc: "Digital Motion Picture Camera", dsub: "Dye Sublimation Printer", epho: "Electrophotographic Printer", esta: "Electrostatic Printer", flex: "Flexography", fprn: "Film Writer", fscn: "Film Scanner", grav: "Gravure", ijet: "Ink Jet Printer", imgs: "Photo Image Setter", mpfr: "Motion Picture Film Recorder", mpfs: "Motion Picture Film Scanner", offs: "Offset Lithography", pjtv: "Projection Television", rpho: "Photographic Paper Printer", rscn: "Reflective Scanner", silk: "Silkscreen", twax: "Thermal Wax Printer", vidc: "Video Camera", vidm: "Video Monitor" }]]);
+  var yt = class extends re2 {
+    static canHandle(e3, t2, i3) {
+      return 237 === e3.getUint8(t2 + 1) && "Photoshop" === e3.getString(t2 + 4, 9) && void 0 !== this.containsIptc8bim(e3, t2, i3);
+    }
+    static headerLength(e3, t2, i3) {
+      let n3, s2 = this.containsIptc8bim(e3, t2, i3);
+      if (void 0 !== s2) return n3 = e3.getUint8(t2 + s2 + 7), n3 % 2 != 0 && (n3 += 1), 0 === n3 && (n3 = 4), s2 + 8 + n3;
+    }
+    static containsIptc8bim(e3, t2, i3) {
+      for (let n3 = 0; n3 < i3; n3++) if (this.isIptcSegmentHead(e3, t2 + n3)) return n3;
+    }
+    static isIptcSegmentHead(e3, t2) {
+      return 56 === e3.getUint8(t2) && 943868237 === e3.getUint32(t2) && 1028 === e3.getUint16(t2 + 4);
+    }
+    parse() {
+      let { raw: e3 } = this, t2 = this.chunk.byteLength - 1, i3 = false;
+      for (let n3 = 0; n3 < t2; n3++) if (28 === this.chunk.getUint8(n3) && 2 === this.chunk.getUint8(n3 + 1)) {
+        i3 = true;
+        let t3 = this.chunk.getUint16(n3 + 3), s2 = this.chunk.getUint8(n3 + 2), r2 = this.chunk.getLatin1String(n3 + 5, t3);
+        e3.set(s2, this.pluralizeValue(e3.get(s2), r2)), n3 += 4 + t3;
+      } else if (i3) break;
+      return this.translate(), this.output;
+    }
+    pluralizeValue(e3, t2) {
+      return void 0 !== e3 ? e3 instanceof Array ? (e3.push(t2), e3) : [e3, t2] : t2;
+    }
+  };
+  c(yt, "type", "iptc"), c(yt, "translateValues", false), c(yt, "reviveValues", false), T.set("iptc", yt), U(E, "iptc", [[0, "ApplicationRecordVersion"], [3, "ObjectTypeReference"], [4, "ObjectAttributeReference"], [5, "ObjectName"], [7, "EditStatus"], [8, "EditorialUpdate"], [10, "Urgency"], [12, "SubjectReference"], [15, "Category"], [20, "SupplementalCategories"], [22, "FixtureIdentifier"], [25, "Keywords"], [26, "ContentLocationCode"], [27, "ContentLocationName"], [30, "ReleaseDate"], [35, "ReleaseTime"], [37, "ExpirationDate"], [38, "ExpirationTime"], [40, "SpecialInstructions"], [42, "ActionAdvised"], [45, "ReferenceService"], [47, "ReferenceDate"], [50, "ReferenceNumber"], [55, "DateCreated"], [60, "TimeCreated"], [62, "DigitalCreationDate"], [63, "DigitalCreationTime"], [65, "OriginatingProgram"], [70, "ProgramVersion"], [75, "ObjectCycle"], [80, "Byline"], [85, "BylineTitle"], [90, "City"], [92, "Sublocation"], [95, "State"], [100, "CountryCode"], [101, "Country"], [103, "OriginalTransmissionReference"], [105, "Headline"], [110, "Credit"], [115, "Source"], [116, "CopyrightNotice"], [118, "Contact"], [120, "Caption"], [121, "LocalCaption"], [122, "Writer"], [125, "RasterizedCaption"], [130, "ImageType"], [131, "ImageOrientation"], [135, "LanguageIdentifier"], [150, "AudioType"], [151, "AudioSamplingRate"], [152, "AudioSamplingResolution"], [153, "AudioDuration"], [154, "AudioOutcue"], [184, "JobID"], [185, "MasterDocumentID"], [186, "ShortDocumentID"], [187, "UniqueDocumentID"], [188, "OwnerID"], [200, "ObjectPreviewFileFormat"], [201, "ObjectPreviewFileVersion"], [202, "ObjectPreviewData"], [221, "Prefs"], [225, "ClassifyState"], [228, "SimilarityIndex"], [230, "DocumentNotes"], [231, "DocumentHistory"], [232, "ExifCameraInfo"], [255, "CatalogSets"]]), U(B, "iptc", [[10, { 0: "0 (reserved)", 1: "1 (most urgent)", 2: "2", 3: "3", 4: "4", 5: "5 (normal urgency)", 6: "6", 7: "7", 8: "8 (least urgent)", 9: "9 (user-defined priority)" }], [75, { a: "Morning", b: "Both Morning and Evening", p: "Evening" }], [131, { L: "Landscape", P: "Portrait", S: "Square" }]]);
+  var full_esm_default = tt;
+
+  // modules/services/plane_photo.js
+  var dispatch5 = dispatch_default("viewerChanged");
+  var _photo;
+  var _wrapper;
+  var imgZoom;
+  var _widthOverflow;
+  function zoomPan(d3_event) {
+    let t2 = d3_event.transform;
+    _photo.call(utilSetTransform, t2.x, t2.y, t2.k);
+  }
+  function zoomBeahvior() {
+    const { width: wrapperWidth, height: wrapperHeight } = _wrapper.node().getBoundingClientRect();
+    const { naturalHeight, naturalWidth } = _photo.node();
+    const intrinsicRatio = naturalWidth / naturalHeight;
+    _widthOverflow = wrapperHeight * intrinsicRatio - wrapperWidth;
+    return zoom_default2().extent([[0, 0], [wrapperWidth, wrapperHeight]]).translateExtent([[0, 0], [wrapperWidth + _widthOverflow, wrapperHeight]]).scaleExtent([1, 15]).on("zoom", zoomPan);
+  }
+  function loadImage(selection2, path) {
+    return new Promise((resolve) => {
+      selection2.attr("src", path);
+      selection2.on("load", () => {
+        resolve(selection2);
+      });
     });
-    if (d2) {
-      return _t("units.area_pair", {
-        area1: area,
-        area2: _t("units." + unit2, {
-          quantity: d2.toLocaleString(locale2, {
-            maximumSignificantDigits: 2
-          })
-        })
+  }
+  var plane_photo_default = {
+    init: async function(context, selection2) {
+      this.event = utilRebind(this, dispatch5, "on");
+      _wrapper = selection2.append("div").attr("class", "photo-frame plane-frame").classed("hide", true);
+      _photo = _wrapper.append("img").attr("class", "plane-photo");
+      context.ui().photoviewer.on("resize.plane", () => {
+        imgZoom = zoomBeahvior();
+        _wrapper.call(imgZoom);
       });
-    } else {
-      return area;
+      await Promise.resolve();
+      return this;
+    },
+    showPhotoFrame: function(context) {
+      const isHidden = context.selectAll(".photo-frame.plane-frame.hide").size();
+      if (isHidden) {
+        context.selectAll(".photo-frame:not(.plane-frame)").classed("hide", true);
+        context.selectAll(".photo-frame.plane-frame").classed("hide", false);
+      }
+      return this;
+    },
+    hidePhotoFrame: function(context) {
+      context.select("photo-frame.plane-frame").classed("hide", false);
+      return this;
+    },
+    selectPhoto: function(data) {
+      dispatch5.call("viewerChanged");
+      loadImage(_photo, "");
+      loadImage(_photo, data.image_path).then(() => {
+        imgZoom = zoomBeahvior();
+        _wrapper.call(imgZoom);
+        _wrapper.call(imgZoom.transform, identity2.translate(-_widthOverflow / 2, 0));
+      });
+      return this;
+    },
+    getYaw: function() {
+      return 0;
     }
-  }
-  function wrap(x, min3, max3) {
-    var d = max3 - min3;
-    return ((x - min3) % d + d) % d + min3;
-  }
-  function clamp2(x, min3, max3) {
-    return Math.max(min3, Math.min(x, max3));
-  }
-  function displayCoordinate(deg, pos, neg) {
-    var locale2 = _mainLocalizer.localeCode();
-    var min3 = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
-    var sec = (min3 - Math.floor(min3)) * 60;
-    var displayDegrees = _t("units.arcdegrees", {
-      quantity: Math.floor(Math.abs(deg)).toLocaleString(locale2)
-    });
-    var displayCoordinate2;
-    if (Math.floor(sec) > 0) {
-      displayCoordinate2 = displayDegrees + _t("units.arcminutes", {
-        quantity: Math.floor(min3).toLocaleString(locale2)
-      }) + _t("units.arcseconds", {
-        quantity: Math.round(sec).toLocaleString(locale2)
+  };
+
+  // modules/svg/local_photos.js
+  var _initialized2 = false;
+  var _enabled2 = false;
+  var minViewfieldZoom = 16;
+  function svgLocalPhotos(projection2, context, dispatch14) {
+    const detected = utilDetect();
+    let layer = select_default2(null);
+    let _fileList;
+    let _photos = [];
+    let _idAutoinc = 0;
+    let _photoFrame;
+    function init2() {
+      if (_initialized2) return;
+      _enabled2 = true;
+      function over(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        d3_event.dataTransfer.dropEffect = "copy";
+      }
+      context.container().attr("dropzone", "copy").on("drop.svgLocalPhotos", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        if (!detected.filedrop) return;
+        drawPhotos.fileList(d3_event.dataTransfer.files, (loaded) => {
+          if (loaded.length > 0) {
+            drawPhotos.fitZoom(false);
+          }
+        });
+      }).on("dragenter.svgLocalPhotos", over).on("dragexit.svgLocalPhotos", over).on("dragover.svgLocalPhotos", over);
+      _initialized2 = true;
+    }
+    function ensureViewerLoaded(context2) {
+      if (_photoFrame) {
+        return Promise.resolve(_photoFrame);
+      }
+      const viewer = context2.container().select(".photoviewer").selectAll(".local-photos-wrapper").data([0]);
+      const viewerEnter = viewer.enter().append("div").attr("class", "photo-wrapper local-photos-wrapper").classed("hide", true);
+      viewerEnter.append("div").attr("class", "photo-attribution photo-attribution-dual fillD");
+      return plane_photo_default.init(context2, viewerEnter).then((planePhotoFrame) => {
+        _photoFrame = planePhotoFrame;
+      });
+    }
+    function click(d3_event, image, zoomTo) {
+      ensureViewerLoaded(context).then(() => {
+        const viewer = context.container().select(".photoviewer").datum(image).classed("hide", false);
+        const viewerWrap = viewer.select(".local-photos-wrapper").classed("hide", false);
+        const attribution = viewerWrap.selectAll(".photo-attribution").text("");
+        if (image.date) {
+          attribution.append("span").text(image.date.toLocaleString());
+        }
+        if (image.name) {
+          attribution.append("span").classed("filename", true).text(image.name);
+        }
+        _photoFrame.selectPhoto({ image_path: "" });
+        image.getSrc().then((src) => {
+          _photoFrame.selectPhoto({ image_path: src }).showPhotoFrame(viewerWrap);
+          setStyles();
+        });
       });
-    } else if (Math.floor(min3) > 0) {
-      displayCoordinate2 = displayDegrees + _t("units.arcminutes", {
-        quantity: Math.round(min3).toLocaleString(locale2)
+      if (zoomTo) {
+        context.map().centerEase(image.loc);
+      }
+    }
+    function transform2(d2) {
+      var svgpoint = projection2(d2.loc);
+      return "translate(" + svgpoint[0] + "," + svgpoint[1] + ")";
+    }
+    function setStyles(hovered) {
+      const viewer = context.container().select(".photoviewer");
+      const selected = viewer.empty() ? void 0 : viewer.datum();
+      context.container().selectAll(".layer-local-photos .viewfield-group").classed("hovered", (d2) => d2.id === (hovered == null ? void 0 : hovered.id)).classed("highlighted", (d2) => d2.id === (hovered == null ? void 0 : hovered.id) || d2.id === (selected == null ? void 0 : selected.id)).classed("currentView", (d2) => d2.id === (selected == null ? void 0 : selected.id));
+    }
+    function display_markers(imageList) {
+      imageList = imageList.filter((image) => isArray_default(image.loc) && isNumber_default(image.loc[0]) && isNumber_default(image.loc[1]));
+      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(imageList, function(d2) {
+        return d2.id;
       });
-    } else {
-      displayCoordinate2 = _t("units.arcdegrees", {
-        quantity: Math.round(Math.abs(deg)).toLocaleString(locale2)
+      groups.exit().remove();
+      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", (d3_event, d2) => setStyles(d2)).on("mouseleave", () => setStyles(null)).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      const markers = groups.merge(groupsEnter).attr("transform", transform2).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      const showViewfields = context.map().zoom() >= minViewfieldZoom;
+      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", function() {
+        var _a3;
+        const d2 = this.parentNode.__data__;
+        return "rotate(".concat(Math.round((_a3 = d2.direction) != null ? _a3 : 0), ",0,0),scale(1.5,1.5),translate(-8,-13)");
+      }).attr("d", "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z").style("visibility", function() {
+        const d2 = this.parentNode.__data__;
+        return isNumber_default(d2.direction) ? "visible" : "hidden";
       });
     }
-    if (deg === 0) {
-      return displayCoordinate2;
-    } else {
-      return _t("units.coordinate", {
-        coordinate: displayCoordinate2,
-        direction: _t("units." + (deg > 0 ? pos : neg))
+    function drawPhotos(selection2) {
+      layer = selection2.selectAll(".layer-local-photos").data(_photos ? [0] : []);
+      layer.exit().remove();
+      const layerEnter = layer.enter().append("g").attr("class", "layer-local-photos");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (_photos) {
+        display_markers(_photos);
+      }
+    }
+    function readFileAsDataURL(file) {
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.onload = () => resolve(reader.result);
+        reader.onerror = (error) => reject(error);
+        reader.readAsDataURL(file);
       });
     }
-  }
-  function dmsCoordinatePair(coord2) {
-    return _t("units.coordinate_pair", {
-      latitude: displayCoordinate(clamp2(coord2[1], -90, 90), "north", "south"),
-      longitude: displayCoordinate(wrap(coord2[0], -180, 180), "east", "west")
-    });
-  }
-  function decimalCoordinatePair(coord2) {
-    return _t("units.coordinate_pair", {
-      latitude: clamp2(coord2[1], -90, 90).toFixed(OSM_PRECISION),
-      longitude: wrap(coord2[0], -180, 180).toFixed(OSM_PRECISION)
-    });
-  }
-
-  // modules/ui/panels/location.js
-  function uiPanelLocation(context) {
-    var currLocation = "";
-    function redraw(selection2) {
-      selection2.html("");
-      var list = selection2.append("ul");
-      var coord2 = context.map().mouseCoordinates();
-      if (coord2.some(isNaN)) {
-        coord2 = context.map().center();
+    async function readmultifiles(files, callback) {
+      const loaded = [];
+      for (const file of files) {
+        try {
+          const exifData = await full_esm_default.parse(file);
+          const photo = {
+            id: _idAutoinc++,
+            name: file.name,
+            getSrc: () => readFileAsDataURL(file),
+            file,
+            loc: [exifData.longitude, exifData.latitude],
+            direction: exifData.GPSImgDirection,
+            date: exifData.CreateDate || exifData.DateTimeOriginal || exifData.ModifyDate
+          };
+          loaded.push(photo);
+          const sameName = _photos.filter((i3) => i3.name === photo.name);
+          if (sameName.length === 0) {
+            _photos.push(photo);
+          } else {
+            const thisContent = await photo.getSrc();
+            const sameNameContent = await Promise.allSettled(sameName.map((i3) => i3.getSrc()));
+            if (!sameNameContent.some((i3) => i3.value === thisContent)) {
+              _photos.push(photo);
+            }
+          }
+        } catch {
+        }
       }
-      list.append("li").text(dmsCoordinatePair(coord2)).append("li").text(decimalCoordinatePair(coord2));
-      selection2.append("div").attr("class", "location-info").text(currLocation || " ");
-      debouncedGetLocation(selection2, coord2);
+      if (typeof callback === "function") callback(loaded);
+      dispatch14.call("change");
     }
-    var debouncedGetLocation = debounce_default(getLocation, 250);
-    function getLocation(selection2, coord2) {
-      if (!services.geocoder) {
-        currLocation = _t("info_panels.location.unknown_location");
-        selection2.selectAll(".location-info").text(currLocation);
-      } else {
-        services.geocoder.reverse(coord2, function(err, result) {
-          currLocation = result ? result.display_name : _t("info_panels.location.unknown_location");
-          selection2.selectAll(".location-info").text(currLocation);
-        });
+    drawPhotos.setFiles = function(fileList, callback) {
+      readmultifiles(Array.from(fileList), callback);
+      return this;
+    };
+    drawPhotos.fileList = function(fileList, callback) {
+      if (!arguments.length) return _fileList;
+      _fileList = fileList;
+      if (!fileList || !fileList.length) return this;
+      drawPhotos.setFiles(_fileList, callback);
+      return this;
+    };
+    drawPhotos.getPhotos = function() {
+      return _photos;
+    };
+    drawPhotos.removePhoto = function(id2) {
+      _photos = _photos.filter((i3) => i3.id !== id2);
+      dispatch14.call("change");
+      return _photos;
+    };
+    drawPhotos.openPhoto = click;
+    drawPhotos.fitZoom = function(force) {
+      const coords = _photos.map((image) => image.loc).filter((l2) => isArray_default(l2) && isNumber_default(l2[0]) && isNumber_default(l2[1]));
+      if (coords.length === 0) return;
+      const extent = coords.map((l2) => geoExtent(l2, l2)).reduce((a2, b2) => a2.extend(b2));
+      const map2 = context.map();
+      var viewport = map2.trimmedExtent().polygon();
+      if (force !== false || !geoPolygonIntersectsPolygon(viewport, coords, true)) {
+        map2.centerZoom(extent.center(), Math.min(18, map2.trimmedExtentZoom(extent)));
       }
+    };
+    function showLayer() {
+      layer.style("display", "block");
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
+      });
     }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.surface().on(("PointerEvent" in window ? "pointer" : "mouse") + "move.info-location", function() {
-        selection2.call(redraw);
+    function hideLayer() {
+      layer.transition().duration(250).style("opacity", 0).on("end", () => {
+        layer.selectAll(".viewfield-group").remove();
+        layer.style("display", "none");
       });
+    }
+    drawPhotos.enabled = function(val) {
+      if (!arguments.length) return _enabled2;
+      _enabled2 = val;
+      if (_enabled2) {
+        showLayer();
+      } else {
+        hideLayer();
+      }
+      dispatch14.call("change");
+      return this;
     };
-    panel.off = function() {
-      context.surface().on(".info-location", null);
+    drawPhotos.hasData = function() {
+      return isArray_default(_photos) && _photos.length > 0;
     };
-    panel.id = "location";
-    panel.label = _t.append("info_panels.location.title");
-    panel.key = _t("info_panels.location.key");
-    return panel;
+    init2();
+    return drawPhotos;
   }
 
-  // modules/ui/panels/measurement.js
-  function uiPanelMeasurement(context) {
-    function radiansToMeters(r) {
-      return r * 63710071809e-4;
-    }
-    function steradiansToSqmeters(r) {
-      return r / (4 * Math.PI) * 510065621724e3;
+  // modules/svg/osmose.js
+  var _layerEnabled2 = false;
+  var _qaService2;
+  function svgOsmose(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(() => dispatch14.call("change"), 1e3);
+    const minZoom5 = 12;
+    let touchLayer = select_default2(null);
+    let drawLayer = select_default2(null);
+    let layerVisible = false;
+    function markerPath(selection2, klass) {
+      selection2.attr("class", klass).attr("transform", "translate(-10, -28)").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
     }
-    function toLineString(feature3) {
-      if (feature3.type === "LineString")
-        return feature3;
-      var result = { type: "LineString", coordinates: [] };
-      if (feature3.type === "Polygon") {
-        result.coordinates = feature3.coordinates[0];
-      } else if (feature3.type === "MultiPolygon") {
-        result.coordinates = feature3.coordinates[0][0];
+    function getService() {
+      if (services.osmose && !_qaService2) {
+        _qaService2 = services.osmose;
+        _qaService2.on("loaded", throttledRedraw);
+      } else if (!services.osmose && _qaService2) {
+        _qaService2 = null;
       }
-      return result;
+      return _qaService2;
     }
-    var _isImperial = !_mainLocalizer.usesMetric();
-    function redraw(selection2) {
-      var graph = context.graph();
-      var selectedNoteID = context.selectedNoteID();
-      var osm = services.osm;
-      var localeCode = _mainLocalizer.localeCode();
-      var heading;
-      var center, location, centroid;
-      var closed, geometry;
-      var totalNodeCount, length = 0, area = 0, distance;
-      if (selectedNoteID && osm) {
-        var note = osm.getNote(selectedNoteID);
-        heading = _t.html("note.note") + " " + selectedNoteID;
-        location = note.loc;
-        geometry = "note";
-      } else {
-        var selectedIDs = context.selectedIDs().filter(function(id2) {
-          return context.hasEntity(id2);
-        });
-        var selected = selectedIDs.map(function(id2) {
-          return context.entity(id2);
-        });
-        heading = selected.length === 1 ? selected[0].id : _t.html("info_panels.selected", { n: selected.length });
-        if (selected.length) {
-          var extent = geoExtent();
-          for (var i2 in selected) {
-            var entity = selected[i2];
-            extent._extend(entity.extent(graph));
-            geometry = entity.geometry(graph);
-            if (geometry === "line" || geometry === "area") {
-              closed = entity.type === "relation" || entity.isClosed() && !entity.isDegenerate();
-              var feature3 = entity.asGeoJSON(graph);
-              length += radiansToMeters(length_default(toLineString(feature3)));
-              centroid = path_default(context.projection).centroid(entity.asGeoJSON(graph));
-              centroid = centroid && context.projection.invert(centroid);
-              if (!centroid || !isFinite(centroid[0]) || !isFinite(centroid[1])) {
-                centroid = entity.extent(graph).center();
-              }
-              if (closed) {
-                area += steradiansToSqmeters(entity.area(graph));
-              }
-            }
-          }
-          if (selected.length > 1) {
-            geometry = null;
-            closed = null;
-            centroid = null;
-          }
-          if (selected.length === 2 && selected[0].type === "node" && selected[1].type === "node") {
-            distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
-          }
-          if (selected.length === 1 && selected[0].type === "node") {
-            location = selected[0].loc;
-          } else {
-            totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
-          }
-          if (!location && !centroid) {
-            center = extent.center();
-          }
-        }
-      }
-      selection2.html("");
-      if (heading) {
-        selection2.append("h4").attr("class", "measurement-heading").html(heading);
-      }
-      var list = selection2.append("ul");
-      var coordItem;
-      if (geometry) {
-        list.append("li").call(_t.append("info_panels.measurement.geometry", { suffix: ":" })).append("span").html(
-          closed ? _t.html("info_panels.measurement.closed_" + geometry) : _t.html("geometry." + geometry)
-        );
+    function editOn() {
+      if (!layerVisible) {
+        layerVisible = true;
+        drawLayer.style("display", "block");
       }
-      if (totalNodeCount) {
-        list.append("li").call(_t.append("info_panels.measurement.node_count", { suffix: ":" })).append("span").text(totalNodeCount.toLocaleString(localeCode));
+    }
+    function editOff() {
+      if (layerVisible) {
+        layerVisible = false;
+        drawLayer.style("display", "none");
+        drawLayer.selectAll(".qaItem.osmose").remove();
+        touchLayer.selectAll(".qaItem.osmose").remove();
       }
-      if (area) {
-        list.append("li").call(_t.append("info_panels.measurement.area", { suffix: ":" })).append("span").text(displayArea(area, _isImperial));
+    }
+    function layerOn() {
+      editOn();
+      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", () => dispatch14.call("change"));
+    }
+    function layerOff() {
+      throttledRedraw.cancel();
+      drawLayer.interrupt();
+      touchLayer.selectAll(".qaItem.osmose").remove();
+      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", () => {
+        editOff();
+        dispatch14.call("change");
+      });
+    }
+    function updateMarkers() {
+      if (!layerVisible || !_layerEnabled2) return;
+      const service = getService();
+      const selectedID = context.selectedErrorID();
+      const data = service ? service.getItems(projection2) : [];
+      const getTransform = svgPointTransform(projection2);
+      const markers = drawLayer.selectAll(".qaItem.osmose").data(data, (d2) => d2.id);
+      markers.exit().remove();
+      const markersEnter = markers.enter().append("g").attr("class", (d2) => "qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.itemType));
+      markersEnter.append("polygon").call(markerPath, "shadow");
+      markersEnter.append("ellipse").attr("cx", 0).attr("cy", 0).attr("rx", 4.5).attr("ry", 2).attr("class", "stroke");
+      markersEnter.append("polygon").attr("fill", (d2) => service.getColor(d2.item)).call(markerPath, "qaItem-fill");
+      markersEnter.append("use").attr("class", "icon-annotation").attr("transform", "translate(-6, -22)").attr("width", "12px").attr("height", "12px").attr("xlink:href", (d2) => d2.icon ? "#" + d2.icon : "");
+      markers.merge(markersEnter).sort(sortY).classed("selected", (d2) => d2.id === selectedID).attr("transform", getTransform);
+      if (touchLayer.empty()) return;
+      const fillClass = context.getDebug("target") ? "pink" : "nocolor";
+      const targets = touchLayer.selectAll(".qaItem.osmose").data(data, (d2) => d2.id);
+      targets.exit().remove();
+      targets.enter().append("rect").attr("width", "20px").attr("height", "30px").attr("x", "-10px").attr("y", "-28px").merge(targets).sort(sortY).attr("class", (d2) => "qaItem ".concat(d2.service, " target ").concat(fillClass, " itemId-").concat(d2.id)).attr("transform", getTransform);
+      function sortY(a2, b2) {
+        return a2.id === selectedID ? 1 : b2.id === selectedID ? -1 : b2.loc[1] - a2.loc[1];
       }
-      if (length) {
-        list.append("li").call(_t.append("info_panels.measurement." + (closed ? "perimeter" : "length"), { suffix: ":" })).append("span").text(displayLength(length, _isImperial));
+    }
+    function drawOsmose(selection2) {
+      const service = getService();
+      const surface = context.surface();
+      if (surface && !surface.empty()) {
+        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
       }
-      if (typeof distance === "number") {
-        list.append("li").call(_t.append("info_panels.measurement.distance", { suffix: ":" })).append("span").text(displayLength(distance, _isImperial));
+      drawLayer = selection2.selectAll(".layer-osmose").data(service ? [0] : []);
+      drawLayer.exit().remove();
+      drawLayer = drawLayer.enter().append("g").attr("class", "layer-osmose").style("display", _layerEnabled2 ? "block" : "none").merge(drawLayer);
+      if (_layerEnabled2) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          service.loadIssues(projection2);
+          updateMarkers();
+        } else {
+          editOff();
+        }
       }
-      if (location) {
-        coordItem = list.append("li").call(_t.append("info_panels.measurement.location", { suffix: ":" }));
-        coordItem.append("span").text(dmsCoordinatePair(location));
-        coordItem.append("span").text(decimalCoordinatePair(location));
+    }
+    drawOsmose.enabled = function(val) {
+      if (!arguments.length) return _layerEnabled2;
+      _layerEnabled2 = val;
+      if (_layerEnabled2) {
+        getService().loadStrings().then(layerOn).catch((err) => {
+          console.log(err);
+        });
+      } else {
+        layerOff();
+        if (context.selectedErrorID()) {
+          context.enter(modeBrowse(context));
+        }
       }
-      if (centroid) {
-        coordItem = list.append("li").call(_t.append("info_panels.measurement.centroid", { suffix: ":" }));
-        coordItem.append("span").text(dmsCoordinatePair(centroid));
-        coordItem.append("span").text(decimalCoordinatePair(centroid));
-      }
-      if (center) {
-        coordItem = list.append("li").call(_t.append("info_panels.measurement.center", { suffix: ":" }));
-        coordItem.append("span").text(dmsCoordinatePair(center));
-        coordItem.append("span").text(decimalCoordinatePair(center));
-      }
-      if (length || area || typeof distance === "number") {
-        var toggle = _isImperial ? "imperial" : "metric";
-        selection2.append("a").call(_t.append("info_panels.measurement." + toggle)).attr("href", "#").attr("class", "button button-toggle-units").on("click", function(d3_event) {
-          d3_event.preventDefault();
-          _isImperial = !_isImperial;
-          selection2.call(redraw);
-        });
+      dispatch14.call("change");
+      return this;
+    };
+    drawOsmose.supported = () => !!getService();
+    return drawOsmose;
+  }
+
+  // modules/svg/streetside.js
+  function svgStreetside(projection2, context, dispatch14) {
+    var throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    var minZoom5 = 14;
+    var minMarkerZoom = 16;
+    var minViewfieldZoom2 = 18;
+    var layer = select_default2(null);
+    var _viewerYaw = 0;
+    var _selectedSequence = null;
+    var _streetside;
+    function init2() {
+      if (svgStreetside.initialized) return;
+      svgStreetside.enabled = false;
+      svgStreetside.initialized = true;
+    }
+    function getService() {
+      if (services.streetside && !_streetside) {
+        _streetside = services.streetside;
+        _streetside.event.on("viewerChanged.svgStreetside", viewerChanged).on("loadedImages.svgStreetside", throttledRedraw);
+      } else if (!services.streetside && _streetside) {
+        _streetside = null;
       }
+      return _streetside;
     }
-    var panel = function(selection2) {
-      selection2.call(redraw);
-      context.map().on("drawn.info-measurement", function() {
-        selection2.call(redraw);
+    function showLayer() {
+      var service = getService();
+      if (!service) return;
+      editOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
       });
-      context.on("enter.info-measurement", function() {
-        selection2.call(redraw);
+    }
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
+    }
+    function editOn() {
+      layer.style("display", "block");
+    }
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, d2) {
+      var service = getService();
+      if (!service) return;
+      if (d2.sequenceKey !== _selectedSequence) {
+        _viewerYaw = 0;
+      }
+      _selectedSequence = d2.sequenceKey;
+      service.ensureViewerLoaded(context).then(function() {
+        service.selectImage(context, d2.key).yaw(_viewerYaw).showViewer(context);
       });
-    };
-    panel.off = function() {
-      context.map().on("drawn.info-measurement", null);
-      context.on("enter.info-measurement", null);
-    };
-    panel.id = "measurement";
-    panel.label = _t.append("info_panels.measurement.title");
-    panel.key = _t("info_panels.measurement.key");
-    return panel;
-  }
-
-  // modules/ui/panels/index.js
-  var uiInfoPanels = {
-    background: uiPanelBackground,
-    history: uiPanelHistory,
-    location: uiPanelLocation,
-    measurement: uiPanelMeasurement
-  };
-
-  // modules/ui/info.js
-  function uiInfo(context) {
-    var ids = Object.keys(uiInfoPanels);
-    var wasActive = ["measurement"];
-    var panels = {};
-    var active = {};
-    ids.forEach(function(k) {
-      if (!panels[k]) {
-        panels[k] = uiInfoPanels[k](context);
-        active[k] = false;
+      context.map().centerEase(d2.loc);
+    }
+    function mouseover(d3_event, d2) {
+      var service = getService();
+      if (service) service.setStyles(context, d2);
+    }
+    function mouseout() {
+      var service = getService();
+      if (service) service.setStyles(context, null);
+    }
+    function transform2(d2) {
+      var t2 = svgPointTransform(projection2)(d2);
+      var rot = d2.ca + _viewerYaw;
+      if (rot) {
+        t2 += " rotate(" + Math.floor(rot) + ",0,0)";
       }
-    });
-    function info(selection2) {
-      function redraw() {
-        var activeids = ids.filter(function(k) {
-          return active[k];
-        }).sort();
-        var containers = infoPanels.selectAll(".panel-container").data(activeids, function(k) {
-          return k;
-        });
-        containers.exit().style("opacity", 1).transition().duration(200).style("opacity", 0).on("end", function(d) {
-          select_default2(this).call(panels[d].off).remove();
+      return t2;
+    }
+    function viewerChanged() {
+      var service = getService();
+      if (!service) return;
+      var viewer = service.viewer();
+      if (!viewer) return;
+      _viewerYaw = viewer.getYaw();
+      if (context.map().isTransformed()) return;
+      layer.selectAll(".viewfield-group.currentView").attr("transform", transform2);
+    }
+    function filterBubbles(bubbles) {
+      var fromDate = context.photos().fromDate();
+      var toDate = context.photos().toDate();
+      var usernames = context.photos().usernames();
+      if (fromDate) {
+        var fromTimestamp = new Date(fromDate).getTime();
+        bubbles = bubbles.filter(function(bubble) {
+          return new Date(bubble.captured_at).getTime() >= fromTimestamp;
         });
-        var enter = containers.enter().append("div").attr("class", function(d) {
-          return "fillD2 panel-container panel-container-" + d;
+      }
+      if (toDate) {
+        var toTimestamp = new Date(toDate).getTime();
+        bubbles = bubbles.filter(function(bubble) {
+          return new Date(bubble.captured_at).getTime() <= toTimestamp;
         });
-        enter.style("opacity", 0).transition().duration(200).style("opacity", 1);
-        var title = enter.append("div").attr("class", "panel-title fillD2");
-        title.append("h3").each(function(d) {
-          return panels[d].label(select_default2(this));
+      }
+      if (usernames) {
+        bubbles = bubbles.filter(function(bubble) {
+          return usernames.indexOf(bubble.captured_by) !== -1;
         });
-        title.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function(d3_event, d) {
-          d3_event.stopImmediatePropagation();
-          d3_event.preventDefault();
-          info.toggle(d);
-        }).call(svgIcon("#iD-icon-close"));
-        enter.append("div").attr("class", function(d) {
-          return "panel-content panel-content-" + d;
+      }
+      return bubbles;
+    }
+    function filterSequences(sequences) {
+      var fromDate = context.photos().fromDate();
+      var toDate = context.photos().toDate();
+      var usernames = context.photos().usernames();
+      if (fromDate) {
+        var fromTimestamp = new Date(fromDate).getTime();
+        sequences = sequences.filter(function(sequences2) {
+          return new Date(sequences2.properties.captured_at).getTime() >= fromTimestamp;
         });
-        infoPanels.selectAll(".panel-content").each(function(d) {
-          select_default2(this).call(panels[d]);
+      }
+      if (toDate) {
+        var toTimestamp = new Date(toDate).getTime();
+        sequences = sequences.filter(function(sequences2) {
+          return new Date(sequences2.properties.captured_at).getTime() <= toTimestamp;
         });
       }
-      info.toggle = function(which) {
-        var activeids = ids.filter(function(k) {
-          return active[k];
+      if (usernames) {
+        sequences = sequences.filter(function(sequences2) {
+          return usernames.indexOf(sequences2.properties.captured_by) !== -1;
         });
-        if (which) {
-          active[which] = !active[which];
-          if (activeids.length === 1 && activeids[0] === which) {
-            wasActive = [which];
-          }
-          context.container().select("." + which + "-panel-toggle-item").classed("active", active[which]).select("input").property("checked", active[which]);
-        } else {
-          if (activeids.length) {
-            wasActive = activeids;
-            activeids.forEach(function(k) {
-              active[k] = false;
-            });
-          } else {
-            wasActive.forEach(function(k) {
-              active[k] = true;
-            });
-          }
-        }
-        redraw();
-      };
-      var infoPanels = selection2.selectAll(".info-panels").data([0]);
-      infoPanels = infoPanels.enter().append("div").attr("class", "info-panels").merge(infoPanels);
-      redraw();
-      context.keybinding().on(uiCmd("\u2318" + _t("info_panels.key")), function(d3_event) {
-        d3_event.stopImmediatePropagation();
-        d3_event.preventDefault();
-        info.toggle();
+      }
+      return sequences;
+    }
+    function update() {
+      var viewer = context.container().select(".photoviewer");
+      var selected = viewer.empty() ? void 0 : viewer.datum();
+      var z2 = ~~context.map().zoom();
+      var showMarkers = z2 >= minMarkerZoom;
+      var showViewfields = z2 >= minViewfieldZoom2;
+      var service = getService();
+      var sequences = [];
+      var bubbles = [];
+      if (context.photos().showsPanoramic()) {
+        sequences = service ? service.sequences(projection2) : [];
+        bubbles = service && showMarkers ? service.bubbles(projection2) : [];
+        sequences = filterSequences(sequences);
+        bubbles = filterBubbles(bubbles);
+      }
+      var traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d2) {
+        return d2.properties.key;
       });
-      ids.forEach(function(k) {
-        var key = _t("info_panels." + k + ".key", { default: null });
-        if (!key)
-          return;
-        context.keybinding().on(uiCmd("\u2318\u21E7" + key), function(d3_event) {
-          d3_event.stopImmediatePropagation();
-          d3_event.preventDefault();
-          info.toggle(k);
-        });
+      traces.exit().remove();
+      traces = traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
+      var groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(bubbles, function(d2) {
+        return d2.key + (d2.sequenceKey ? "v1" : "v0");
       });
+      groups.exit().remove();
+      var groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      var markers = groups.merge(groupsEnter).sort(function(a2, b2) {
+        return a2 === selected ? 1 : b2 === selected ? -1 : b2.loc[1] - a2.loc[1];
+      }).attr("transform", transform2).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      var viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
+      function viewfieldPath() {
+        var d2 = this.parentNode.__data__;
+        if (d2.pano) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
+      }
     }
-    return info;
-  }
-
-  // modules/ui/intro/helper.js
-  function pointBox(loc, context) {
-    var rect = context.surfaceRect();
-    var point = context.curtainProjection(loc);
-    return {
-      left: point[0] + rect.left - 40,
-      top: point[1] + rect.top - 60,
-      width: 80,
-      height: 90
-    };
-  }
-  function pad(locOrBox, padding, context) {
-    var box;
-    if (locOrBox instanceof Array) {
-      var rect = context.surfaceRect();
-      var point = context.curtainProjection(locOrBox);
-      box = {
-        left: point[0] + rect.left,
-        top: point[1] + rect.top
-      };
-    } else {
-      box = locOrBox;
+    function drawImages(selection2) {
+      var enabled = svgStreetside.enabled;
+      var service = getService();
+      layer = selection2.selectAll(".layer-streetside-images").data(service ? [0] : []);
+      layer.exit().remove();
+      var layerEnter = layer.enter().append("g").attr("class", "layer-streetside-images").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "sequences");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          update();
+          service.loadBubbles(projection2);
+        } else {
+          editOff();
+        }
+      }
     }
-    return {
-      left: box.left - padding,
-      top: box.top - padding,
-      width: (box.width || 0) + 2 * padding,
-      height: (box.width || 0) + 2 * padding
+    drawImages.enabled = function(_2) {
+      if (!arguments.length) return svgStreetside.enabled;
+      svgStreetside.enabled = _2;
+      if (svgStreetside.enabled) {
+        showLayer();
+        context.photos().on("change.streetside", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.streetside", null);
+      }
+      dispatch14.call("change");
+      return this;
     };
+    drawImages.supported = function() {
+      return !!getService();
+    };
+    drawImages.rendered = function(zoom) {
+      return zoom >= minZoom5;
+    };
+    init2();
+    return drawImages;
   }
-  function icon(name, svgklass, useklass) {
-    return '<svg class="icon ' + (svgklass || "") + '"><use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : "") + "></use></svg>";
-  }
-  var helpStringReplacements;
-  function helpHtml(id2, replacements) {
-    if (!helpStringReplacements) {
-      helpStringReplacements = {
-        point_icon: icon("#iD-icon-point", "inline"),
-        line_icon: icon("#iD-icon-line", "inline"),
-        area_icon: icon("#iD-icon-area", "inline"),
-        note_icon: icon("#iD-icon-note", "inline add-note"),
-        plus: icon("#iD-icon-plus", "inline"),
-        minus: icon("#iD-icon-minus", "inline"),
-        layers_icon: icon("#iD-icon-layers", "inline"),
-        data_icon: icon("#iD-icon-data", "inline"),
-        inspect: icon("#iD-icon-inspect", "inline"),
-        help_icon: icon("#iD-icon-help", "inline"),
-        undo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo", "inline"),
-        redo_icon: icon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-undo" : "#iD-icon-redo", "inline"),
-        save_icon: icon("#iD-icon-save", "inline"),
-        circularize_icon: icon("#iD-operation-circularize", "inline operation"),
-        continue_icon: icon("#iD-operation-continue", "inline operation"),
-        copy_icon: icon("#iD-operation-copy", "inline operation"),
-        delete_icon: icon("#iD-operation-delete", "inline operation"),
-        disconnect_icon: icon("#iD-operation-disconnect", "inline operation"),
-        downgrade_icon: icon("#iD-operation-downgrade", "inline operation"),
-        extract_icon: icon("#iD-operation-extract", "inline operation"),
-        merge_icon: icon("#iD-operation-merge", "inline operation"),
-        move_icon: icon("#iD-operation-move", "inline operation"),
-        orthogonalize_icon: icon("#iD-operation-orthogonalize", "inline operation"),
-        paste_icon: icon("#iD-operation-paste", "inline operation"),
-        reflect_long_icon: icon("#iD-operation-reflect-long", "inline operation"),
-        reflect_short_icon: icon("#iD-operation-reflect-short", "inline operation"),
-        reverse_icon: icon("#iD-operation-reverse", "inline operation"),
-        rotate_icon: icon("#iD-operation-rotate", "inline operation"),
-        split_icon: icon("#iD-operation-split", "inline operation"),
-        straighten_icon: icon("#iD-operation-straighten", "inline operation"),
-        leftclick: icon("#iD-walkthrough-mouse-left", "inline operation"),
-        rightclick: icon("#iD-walkthrough-mouse-right", "inline operation"),
-        mousewheel_icon: icon("#iD-walkthrough-mousewheel", "inline operation"),
-        tap_icon: icon("#iD-walkthrough-tap", "inline operation"),
-        doubletap_icon: icon("#iD-walkthrough-doubletap", "inline operation"),
-        longpress_icon: icon("#iD-walkthrough-longpress", "inline operation"),
-        touchdrag_icon: icon("#iD-walkthrough-touchdrag", "inline operation"),
-        pinch_icon: icon("#iD-walkthrough-pinch-apart", "inline operation"),
-        shift: uiCmd.display("\u21E7"),
-        alt: uiCmd.display("\u2325"),
-        return: uiCmd.display("\u21B5"),
-        esc: _t.html("shortcuts.key.esc"),
-        space: _t.html("shortcuts.key.space"),
-        add_note_key: _t.html("modes.add_note.key"),
-        help_key: _t.html("help.key"),
-        shortcuts_key: _t.html("shortcuts.toggle.key"),
-        save: _t.html("save.title"),
-        undo: _t.html("undo.title"),
-        redo: _t.html("redo.title"),
-        upload: _t.html("commit.save"),
-        point: _t.html("modes.add_point.title"),
-        line: _t.html("modes.add_line.title"),
-        area: _t.html("modes.add_area.title"),
-        note: _t.html("modes.add_note.label"),
-        circularize: _t.html("operations.circularize.title"),
-        continue: _t.html("operations.continue.title"),
-        copy: _t.html("operations.copy.title"),
-        delete: _t.html("operations.delete.title"),
-        disconnect: _t.html("operations.disconnect.title"),
-        downgrade: _t.html("operations.downgrade.title"),
-        extract: _t.html("operations.extract.title"),
-        merge: _t.html("operations.merge.title"),
-        move: _t.html("operations.move.title"),
-        orthogonalize: _t.html("operations.orthogonalize.title"),
-        paste: _t.html("operations.paste.title"),
-        reflect_long: _t.html("operations.reflect.title.long"),
-        reflect_short: _t.html("operations.reflect.title.short"),
-        reverse: _t.html("operations.reverse.title"),
-        rotate: _t.html("operations.rotate.title"),
-        split: _t.html("operations.split.title"),
-        straighten: _t.html("operations.straighten.title"),
-        map_data: _t.html("map_data.title"),
-        osm_notes: _t.html("map_data.layers.notes.title"),
-        fields: _t.html("inspector.fields"),
-        tags: _t.html("inspector.tags"),
-        relations: _t.html("inspector.relations"),
-        new_relation: _t.html("inspector.new_relation"),
-        turn_restrictions: _t.html("_tagging.presets.fields.restrictions.label"),
-        background_settings: _t.html("background.description"),
-        imagery_offset: _t.html("background.fix_misalignment"),
-        start_the_walkthrough: _t.html("splash.walkthrough"),
-        help: _t.html("help.title"),
-        ok: _t.html("intro.ok")
-      };
-      for (var key in helpStringReplacements) {
-        helpStringReplacements[key] = { html: helpStringReplacements[key] };
+
+  // modules/svg/vegbilder.js
+  function svgVegbilder(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(() => dispatch14.call("change"), 1e3);
+    const minZoom5 = 14;
+    const minMarkerZoom = 16;
+    const minViewfieldZoom2 = 18;
+    let layer = select_default2(null);
+    let _viewerYaw = 0;
+    let _vegbilder;
+    function init2() {
+      if (svgVegbilder.initialized) return;
+      svgVegbilder.enabled = false;
+      svgVegbilder.initialized = true;
+    }
+    function getService() {
+      if (services.vegbilder && !_vegbilder) {
+        _vegbilder = services.vegbilder;
+        _vegbilder.event.on("viewerChanged.svgVegbilder", viewerChanged).on("loadedImages.svgVegbilder", throttledRedraw);
+      } else if (!services.vegbilder && _vegbilder) {
+        _vegbilder = null;
       }
+      return _vegbilder;
     }
-    var reps;
-    if (replacements) {
-      reps = Object.assign(replacements, helpStringReplacements);
-    } else {
-      reps = helpStringReplacements;
+    function showLayer() {
+      const service = getService();
+      if (!service) return;
+      editOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", () => dispatch14.call("change"));
     }
-    return _t.html(id2, reps).replace(/\`(.*?)\`/g, "<kbd>$1</kbd>");
-  }
-  function slugify(text2) {
-    return text2.toString().toLowerCase().replace(/\s+/g, "-").replace(/[^\w\-]+/g, "").replace(/\-\-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
-  }
-  var missingStrings = {};
-  function checkKey(key, text2) {
-    if (_t(key, { default: void 0 }) === void 0) {
-      if (missingStrings.hasOwnProperty(key))
-        return;
-      missingStrings[key] = text2;
-      var missing = key + ": " + text2;
-      if (typeof console !== "undefined")
-        console.log(missing);
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
     }
-  }
-  function localize(obj) {
-    var key;
-    var name = obj.tags && obj.tags.name;
-    if (name) {
-      key = "intro.graph.name." + slugify(name);
-      obj.tags.name = _t(key, { default: name });
-      checkKey(key, name);
+    function editOn() {
+      layer.style("display", "block");
     }
-    var street = obj.tags && obj.tags["addr:street"];
-    if (street) {
-      key = "intro.graph.name." + slugify(street);
-      obj.tags["addr:street"] = _t(key, { default: street });
-      checkKey(key, street);
-      var addrTags = [
-        "block_number",
-        "city",
-        "county",
-        "district",
-        "hamlet",
-        "neighbourhood",
-        "postcode",
-        "province",
-        "quarter",
-        "state",
-        "subdistrict",
-        "suburb"
-      ];
-      addrTags.forEach(function(k) {
-        var key2 = "intro.graph." + k;
-        var tag = "addr:" + k;
-        var val = obj.tags && obj.tags[tag];
-        var str2 = _t(key2, { default: val });
-        if (str2) {
-          if (str2.match(/^<.*>$/) !== null) {
-            delete obj.tags[tag];
-          } else {
-            obj.tags[tag] = str2;
-          }
-        }
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, d2) {
+      const service = getService();
+      if (!service) return;
+      service.ensureViewerLoaded(context).then(() => {
+        service.selectImage(context, d2.key).showViewer(context);
       });
+      context.map().centerEase(d2.loc);
     }
-    return obj;
-  }
-  function isMostlySquare(points) {
-    var threshold = 15;
-    var lowerBound = Math.cos((90 - threshold) * Math.PI / 180);
-    var upperBound = Math.cos(threshold * Math.PI / 180);
-    for (var i2 = 0; i2 < points.length; i2++) {
-      var a = points[(i2 - 1 + points.length) % points.length];
-      var origin = points[i2];
-      var b = points[(i2 + 1) % points.length];
-      var dotp = geoVecNormalizedDot(a, b, origin);
-      var mag = Math.abs(dotp);
-      if (mag > lowerBound && mag < upperBound) {
-        return false;
+    function mouseover(d3_event, d2) {
+      const service = getService();
+      if (service) service.setStyles(context, d2);
+    }
+    function mouseout() {
+      const service = getService();
+      if (service) service.setStyles(context, null);
+    }
+    function transform2(d2, selected) {
+      let t2 = svgPointTransform(projection2)(d2);
+      let rot = d2.ca;
+      if (d2 === selected) {
+        rot += _viewerYaw;
+      }
+      if (rot) {
+        t2 += " rotate(" + Math.floor(rot) + ",0,0)";
       }
+      return t2;
     }
-    return true;
-  }
-  function selectMenuItem(context, operation) {
-    return context.container().select(".edit-menu .edit-menu-item-" + operation);
-  }
-  function transitionTime(point1, point2) {
-    var distance = geoSphericalDistance(point1, point2);
-    if (distance === 0) {
-      return 0;
-    } else if (distance < 80) {
-      return 500;
-    } else {
-      return 1e3;
+    function viewerChanged() {
+      const service = getService();
+      if (!service) return;
+      const frame2 = service.photoFrame();
+      _viewerYaw = frame2.getYaw();
+      if (context.map().isTransformed()) return;
+      layer.selectAll(".viewfield-group.currentView").attr("transform", (d2) => transform2(d2, d2));
     }
-  }
-
-  // modules/ui/toggle.js
-  function uiToggle(show, callback) {
-    return function(selection2) {
-      selection2.style("opacity", show ? 0 : 1).classed("hide", false).transition().style("opacity", show ? 1 : 0).on("end", function() {
-        select_default2(this).classed("hide", !show).style("opacity", null);
-        if (callback)
-          callback.apply(this);
-      });
-    };
-  }
-
-  // modules/ui/curtain.js
-  function uiCurtain(containerNode) {
-    var surface = select_default2(null), tooltip = select_default2(null), darkness = select_default2(null);
-    function curtain(selection2) {
-      surface = selection2.append("svg").attr("class", "curtain").style("top", 0).style("left", 0);
-      darkness = surface.append("path").attr("x", 0).attr("y", 0).attr("class", "curtain-darkness");
-      select_default2(window).on("resize.curtain", resize);
-      tooltip = selection2.append("div").attr("class", "tooltip");
-      tooltip.append("div").attr("class", "popover-arrow");
-      tooltip.append("div").attr("class", "popover-inner");
-      resize();
-      function resize() {
-        surface.attr("width", containerNode.clientWidth).attr("height", containerNode.clientHeight);
-        curtain.cut(darkness.datum());
+    function filterImages(images) {
+      const photoContext = context.photos();
+      const fromDateString = photoContext.fromDate();
+      const toDateString = photoContext.toDate();
+      const showsFlat = photoContext.showsFlat();
+      const showsPano = photoContext.showsPanoramic();
+      if (fromDateString) {
+        const fromDate = new Date(fromDateString);
+        images = images.filter((image) => image.captured_at.getTime() >= fromDate.getTime());
+      }
+      if (toDateString) {
+        const toDate = new Date(toDateString);
+        images = images.filter((image) => image.captured_at.getTime() <= toDate.getTime());
+      }
+      if (!showsPano) {
+        images = images.filter((image) => !image.is_sphere);
       }
+      if (!showsFlat) {
+        images = images.filter((image) => image.is_sphere);
+      }
+      return images;
     }
-    curtain.reveal = function(box, html2, options2) {
-      options2 = options2 || {};
-      if (typeof box === "string") {
-        box = select_default2(box).node();
+    function filterSequences(sequences) {
+      const photoContext = context.photos();
+      const fromDateString = photoContext.fromDate();
+      const toDateString = photoContext.toDate();
+      const showsFlat = photoContext.showsFlat();
+      const showsPano = photoContext.showsPanoramic();
+      if (fromDateString) {
+        const fromDate = new Date(fromDateString);
+        sequences = sequences.filter(({ images }) => images[0].captured_at.getTime() >= fromDate.getTime());
       }
-      if (box && box.getBoundingClientRect) {
-        box = copyBox(box.getBoundingClientRect());
-        var containerRect = containerNode.getBoundingClientRect();
-        box.top -= containerRect.top;
-        box.left -= containerRect.left;
+      if (toDateString) {
+        const toDate = new Date(toDateString);
+        sequences = sequences.filter(({ images }) => images[images.length - 1].captured_at.getTime() <= toDate.getTime());
       }
-      if (box && options2.padding) {
-        box.top -= options2.padding;
-        box.left -= options2.padding;
-        box.bottom += options2.padding;
-        box.right += options2.padding;
-        box.height += options2.padding * 2;
-        box.width += options2.padding * 2;
+      if (!showsPano) {
+        sequences = sequences.filter(({ images }) => !images[0].is_sphere);
       }
-      var tooltipBox;
-      if (options2.tooltipBox) {
-        tooltipBox = options2.tooltipBox;
-        if (typeof tooltipBox === "string") {
-          tooltipBox = select_default2(tooltipBox).node();
-        }
-        if (tooltipBox && tooltipBox.getBoundingClientRect) {
-          tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
-        }
-      } else {
-        tooltipBox = box;
+      if (!showsFlat) {
+        sequences = sequences.filter(({ images }) => images[0].is_sphere);
       }
-      if (tooltipBox && html2) {
-        if (html2.indexOf("**") !== -1) {
-          if (html2.indexOf("<span") === 0) {
-            html2 = html2.replace(/^(<span.*?>)(.+?)(\*\*)/, "$1<span>$2</span>$3");
-          } else {
-            html2 = html2.replace(/^(.+?)(\*\*)/, "<span>$1</span>$2");
-          }
-          html2 = html2.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
-        }
-        html2 = html2.replace(/\*(.*?)\*/g, "<em>$1</em>");
-        html2 = html2.replace(/\{br\}/g, "<br/><br/>");
-        if (options2.buttonText && options2.buttonCallback) {
-          html2 += '<div class="button-section"><button href="#" class="button action">' + options2.buttonText + "</button></div>";
-        }
-        var classes = "curtain-tooltip popover tooltip arrowed in " + (options2.tooltipClass || "");
-        tooltip.classed(classes, true).selectAll(".popover-inner").html(html2);
-        if (options2.buttonText && options2.buttonCallback) {
-          var button = tooltip.selectAll(".button-section .button.action");
-          button.on("click", function(d3_event) {
-            d3_event.preventDefault();
-            options2.buttonCallback();
-          });
-        }
-        var tip = copyBox(tooltip.node().getBoundingClientRect()), w = containerNode.clientWidth, h = containerNode.clientHeight, tooltipWidth = 200, tooltipArrow = 5, side, pos;
-        if (options2.tooltipClass === "intro-mouse") {
-          tip.height += 80;
-        }
-        if (tooltipBox.top + tooltipBox.height > h) {
-          tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
-        }
-        if (tooltipBox.left + tooltipBox.width > w) {
-          tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
-        }
-        if (tooltipBox.top + tooltipBox.height < 100) {
-          side = "bottom";
-          pos = [
-            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
-            tooltipBox.top + tooltipBox.height
-          ];
-        } else if (tooltipBox.top > h - 140) {
-          side = "top";
-          pos = [
-            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
-            tooltipBox.top - tip.height
-          ];
+      return sequences;
+    }
+    function update() {
+      const viewer = context.container().select(".photoviewer");
+      const selected = viewer.empty() ? void 0 : viewer.datum();
+      const z2 = ~~context.map().zoom();
+      const showMarkers = z2 >= minMarkerZoom;
+      const showViewfields = z2 >= minViewfieldZoom2;
+      const service = getService();
+      let sequences = [];
+      let images = [];
+      if (service) {
+        service.loadImages(context);
+        sequences = service.sequences(projection2);
+        images = showMarkers ? service.images(projection2) : [];
+        images = filterImages(images);
+        sequences = filterSequences(sequences);
+      }
+      let traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, (d2) => d2.key);
+      traces.exit().remove();
+      traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
+      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, (d2) => d2.key);
+      groups.exit().remove();
+      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      const markers = groups.merge(groupsEnter).sort((a2, b2) => {
+        return a2 === selected ? 1 : b2 === selected ? -1 : b2.loc[1] - a2.loc[1];
+      }).attr("transform", (d2) => transform2(d2, selected)).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
+      function viewfieldPath() {
+        const d2 = this.parentNode.__data__;
+        if (d2.is_sphere) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
         } else {
-          var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
-          if (_mainLocalizer.textDirection() === "rtl") {
-            if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
-              side = "right";
-              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
-            } else {
-              side = "left";
-              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
-            }
-          } else {
-            if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
-              side = "left";
-              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
-            } else {
-              side = "right";
-              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
-            }
-          }
-        }
-        if (options2.duration !== 0 || !tooltip.classed(side)) {
-          tooltip.call(uiToggle(true));
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
         }
-        tooltip.style("top", pos[1] + "px").style("left", pos[0] + "px").attr("class", classes + " " + side);
-        var shiftY = 0;
-        if (side === "left" || side === "right") {
-          if (pos[1] < 60) {
-            shiftY = 60 - pos[1];
-          } else if (pos[1] + tip.height > h - 100) {
-            shiftY = h - pos[1] - tip.height - 100;
-          }
+      }
+    }
+    function drawImages(selection2) {
+      const enabled = svgVegbilder.enabled;
+      const service = getService();
+      layer = selection2.selectAll(".layer-vegbilder").data(service ? [0] : []);
+      layer.exit().remove();
+      const layerEnter = layer.enter().append("g").attr("class", "layer-vegbilder").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "sequences");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          update();
+          service.loadImages(context);
+        } else {
+          editOff();
         }
-        tooltip.selectAll(".popover-inner").style("top", shiftY + "px");
-      } else {
-        tooltip.classed("in", false).call(uiToggle(false));
       }
-      curtain.cut(box, options2.duration);
-      return tooltip;
-    };
-    curtain.cut = function(datum2, duration) {
-      darkness.datum(datum2).interrupt();
-      var selection2;
-      if (duration === 0) {
-        selection2 = darkness;
+    }
+    drawImages.enabled = function(_2) {
+      if (!arguments.length) return svgVegbilder.enabled;
+      svgVegbilder.enabled = _2;
+      if (svgVegbilder.enabled) {
+        showLayer();
+        context.photos().on("change.vegbilder", update);
       } else {
-        selection2 = darkness.transition().duration(duration || 600).ease(linear2);
+        hideLayer();
+        context.photos().on("change.vegbilder", null);
       }
-      selection2.attr("d", function(d) {
-        var containerWidth = containerNode.clientWidth;
-        var containerHeight = containerNode.clientHeight;
-        var string = "M 0,0 L 0," + containerHeight + " L " + containerWidth + "," + containerHeight + "L" + containerWidth + ",0 Z";
-        if (!d)
-          return string;
-        return string + "M" + d.left + "," + d.top + "L" + d.left + "," + (d.top + d.height) + "L" + (d.left + d.width) + "," + (d.top + d.height) + "L" + (d.left + d.width) + "," + d.top + "Z";
-      });
+      dispatch14.call("change");
+      return this;
     };
-    curtain.remove = function() {
-      surface.remove();
-      tooltip.remove();
-      select_default2(window).on("resize.curtain", null);
+    drawImages.supported = function() {
+      return !!getService();
     };
-    function copyBox(src) {
-      return {
-        top: src.top,
-        right: src.right,
-        bottom: src.bottom,
-        left: src.left,
-        width: src.width,
-        height: src.height
-      };
-    }
-    return curtain;
+    drawImages.rendered = function(zoom) {
+      return zoom >= minZoom5;
+    };
+    drawImages.validHere = function(extent, zoom) {
+      return zoom >= minZoom5 - 2 && getService().validHere(extent);
+    };
+    init2();
+    return drawImages;
   }
 
-  // modules/ui/intro/welcome.js
-  function uiIntroWelcome(context, reveal) {
-    var dispatch10 = dispatch_default("done");
-    var chapter = {
-      title: "intro.welcome.title"
-    };
-    function welcome() {
-      context.map().centerZoom([-85.63591, 41.94285], 19);
-      reveal(
-        ".intro-nav-wrap .chapter-welcome",
-        helpHtml("intro.welcome.welcome"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: practice }
-      );
+  // modules/svg/mapillary_images.js
+  function svgMapillaryImages(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    const minZoom5 = 12;
+    const minMarkerZoom = 16;
+    const minViewfieldZoom2 = 18;
+    let layer = select_default2(null);
+    let _mapillary;
+    function init2() {
+      if (svgMapillaryImages.initialized) return;
+      svgMapillaryImages.enabled = false;
+      svgMapillaryImages.initialized = true;
     }
-    function practice() {
-      reveal(
-        ".intro-nav-wrap .chapter-welcome",
-        helpHtml("intro.welcome.practice"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: words }
-      );
+    function getService() {
+      if (services.mapillary && !_mapillary) {
+        _mapillary = services.mapillary;
+        _mapillary.event.on("loadedImages", throttledRedraw);
+      } else if (!services.mapillary && _mapillary) {
+        _mapillary = null;
+      }
+      return _mapillary;
     }
-    function words() {
-      reveal(
-        ".intro-nav-wrap .chapter-welcome",
-        helpHtml("intro.welcome.words"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: chapters }
-      );
+    function showLayer() {
+      const service = getService();
+      if (!service) return;
+      editOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
+      });
     }
-    function chapters() {
-      dispatch10.call("done");
-      reveal(
-        ".intro-nav-wrap .chapter-navigation",
-        helpHtml("intro.welcome.chapters", { next: _t("intro.navigation.title") })
-      );
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
     }
-    chapter.enter = function() {
-      welcome();
-    };
-    chapter.exit = function() {
-      context.container().select(".curtain-tooltip.intro-mouse").selectAll(".counter").remove();
-    };
-    chapter.restart = function() {
-      chapter.exit();
-      chapter.enter();
-    };
-    return utilRebind(chapter, dispatch10, "on");
-  }
-
-  // modules/ui/intro/navigation.js
-  function uiIntroNavigation(context, reveal) {
-    var dispatch10 = dispatch_default("done");
-    var timeouts = [];
-    var hallId = "n2061";
-    var townHall = [-85.63591, 41.94285];
-    var springStreetId = "w397";
-    var springStreetEndId = "n1834";
-    var springStreet = [-85.63582, 41.94255];
-    var onewayField = _mainPresetIndex.field("oneway");
-    var maxspeedField = _mainPresetIndex.field("maxspeed");
-    var chapter = {
-      title: "intro.navigation.title"
-    };
-    function timeout2(f2, t) {
-      timeouts.push(window.setTimeout(f2, t));
+    function editOn() {
+      layer.style("display", "block");
     }
-    function eventCancel(d3_event) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
     }
-    function isTownHallSelected() {
-      var ids = context.selectedIDs();
-      return ids.length === 1 && ids[0] === hallId;
+    function click(d3_event, image) {
+      const service = getService();
+      if (!service) return;
+      service.ensureViewerLoaded(context).then(function() {
+        service.selectImage(context, image.id).showViewer(context);
+      });
+      context.map().centerEase(image.loc);
     }
-    function dragMap() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var msec = transitionTime(townHall, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
+    function mouseover(d3_event, image) {
+      const service = getService();
+      if (service) service.setStyles(context, image);
+    }
+    function mouseout() {
+      const service = getService();
+      if (service) service.setStyles(context, null);
+    }
+    function transform2(d2) {
+      let t2 = svgPointTransform(projection2)(d2);
+      if (d2.ca) {
+        t2 += " rotate(" + Math.floor(d2.ca) + ",0,0)";
       }
-      context.map().centerZoomEase(townHall, 19, msec);
-      timeout2(function() {
-        var centerStart = context.map().center();
-        var textId = context.lastPointerType() === "mouse" ? "drag" : "drag_touch";
-        var dragString = helpHtml("intro.navigation.map_info") + "{br}" + helpHtml("intro.navigation." + textId);
-        reveal(".surface", dragString);
-        context.map().on("drawn.intro", function() {
-          reveal(".surface", dragString, { duration: 0 });
+      return t2;
+    }
+    function filterImages(images) {
+      const showsPano = context.photos().showsPanoramic();
+      const showsFlat = context.photos().showsFlat();
+      const fromDate = context.photos().fromDate();
+      const toDate = context.photos().toDate();
+      if (!showsPano || !showsFlat) {
+        images = images.filter(function(image) {
+          if (image.is_pano) return showsPano;
+          return showsFlat;
         });
-        context.map().on("move.intro", function() {
-          var centerNow = context.map().center();
-          if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
-            context.map().on("move.intro", null);
-            timeout2(function() {
-              continueTo(zoomMap);
-            }, 3e3);
+      }
+      if (fromDate) {
+        images = images.filter(function(image) {
+          return new Date(image.captured_at).getTime() >= new Date(fromDate).getTime();
+        });
+      }
+      if (toDate) {
+        images = images.filter(function(image) {
+          return new Date(image.captured_at).getTime() <= new Date(toDate).getTime();
+        });
+      }
+      return images;
+    }
+    function filterSequences(sequences) {
+      const showsPano = context.photos().showsPanoramic();
+      const showsFlat = context.photos().showsFlat();
+      const fromDate = context.photos().fromDate();
+      const toDate = context.photos().toDate();
+      if (!showsPano || !showsFlat) {
+        sequences = sequences.filter(function(sequence) {
+          if (sequence.properties.hasOwnProperty("is_pano")) {
+            if (sequence.properties.is_pano) return showsPano;
+            return showsFlat;
           }
+          return false;
+        });
+      }
+      if (fromDate) {
+        sequences = sequences.filter(function(sequence) {
+          return new Date(sequence.properties.captured_at).getTime() >= new Date(fromDate).getTime().toString();
+        });
+      }
+      if (toDate) {
+        sequences = sequences.filter(function(sequence) {
+          return new Date(sequence.properties.captured_at).getTime() <= new Date(toDate).getTime().toString();
         });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
       }
+      return sequences;
     }
-    function zoomMap() {
-      var zoomStart = context.map().zoom();
-      var textId = context.lastPointerType() === "mouse" ? "zoom" : "zoom_touch";
-      var zoomString = helpHtml("intro.navigation." + textId);
-      reveal(".surface", zoomString);
-      context.map().on("drawn.intro", function() {
-        reveal(".surface", zoomString, { duration: 0 });
+    function update() {
+      const z2 = ~~context.map().zoom();
+      const showMarkers = z2 >= minMarkerZoom;
+      const showViewfields = z2 >= minViewfieldZoom2;
+      const service = getService();
+      let sequences = service ? service.sequences(projection2) : [];
+      let images = service && showMarkers ? service.images(projection2) : [];
+      images = filterImages(images);
+      sequences = filterSequences(sequences, service);
+      service.filterViewer(context);
+      let traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d2) {
+        return d2.properties.id;
       });
-      context.map().on("move.intro", function() {
-        if (context.map().zoom() !== zoomStart) {
-          context.map().on("move.intro", null);
-          timeout2(function() {
-            continueTo(features2);
-          }, 3e3);
-        }
+      traces.exit().remove();
+      traces = traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
+      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, function(d2) {
+        return d2.id;
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
+      groups.exit().remove();
+      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      const markers = groups.merge(groupsEnter).sort(function(a2, b2) {
+        return b2.loc[1] - a2.loc[1];
+      }).attr("transform", transform2).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").classed("pano", function() {
+        return this.parentNode.__data__.is_pano;
+      }).attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
+      function viewfieldPath() {
+        if (this.parentNode.__data__.is_pano) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
       }
     }
-    function features2() {
-      var onClick = function() {
-        continueTo(pointsLinesAreas);
-      };
-      reveal(
-        ".surface",
-        helpHtml("intro.navigation.features"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("drawn.intro", function() {
-        reveal(
-          ".surface",
-          helpHtml("intro.navigation.features"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("drawn.intro", null);
-        nextStep();
+    function drawImages(selection2) {
+      const enabled = svgMapillaryImages.enabled;
+      const service = getService();
+      layer = selection2.selectAll(".layer-mapillary").data(service ? [0] : []);
+      layer.exit().remove();
+      const layerEnter = layer.enter().append("g").attr("class", "layer-mapillary").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "sequences");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          update();
+          service.loadImages(projection2);
+        } else {
+          editOff();
+        }
       }
     }
-    function pointsLinesAreas() {
-      var onClick = function() {
-        continueTo(nodesWays);
-      };
-      reveal(
-        ".surface",
-        helpHtml("intro.navigation.points_lines_areas"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("drawn.intro", function() {
-        reveal(
-          ".surface",
-          helpHtml("intro.navigation.points_lines_areas"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("drawn.intro", null);
-        nextStep();
+    drawImages.enabled = function(_2) {
+      if (!arguments.length) return svgMapillaryImages.enabled;
+      svgMapillaryImages.enabled = _2;
+      if (svgMapillaryImages.enabled) {
+        showLayer();
+        context.photos().on("change.mapillary_images", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.mapillary_images", null);
       }
+      dispatch14.call("change");
+      return this;
+    };
+    drawImages.supported = function() {
+      return !!getService();
+    };
+    drawImages.rendered = function(zoom) {
+      return zoom >= minZoom5;
+    };
+    init2();
+    return drawImages;
+  }
+
+  // modules/svg/mapillary_position.js
+  function svgMapillaryPosition(projection2, context) {
+    const throttledRedraw = throttle_default(function() {
+      update();
+    }, 1e3);
+    const minZoom5 = 12;
+    const minViewfieldZoom2 = 18;
+    let layer = select_default2(null);
+    let _mapillary;
+    let viewerCompassAngle;
+    function init2() {
+      if (svgMapillaryPosition.initialized) return;
+      svgMapillaryPosition.initialized = true;
     }
-    function nodesWays() {
-      var onClick = function() {
-        continueTo(clickTownHall);
-      };
-      reveal(
-        ".surface",
-        helpHtml("intro.navigation.nodes_ways"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("drawn.intro", function() {
-        reveal(
-          ".surface",
-          helpHtml("intro.navigation.nodes_ways"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("drawn.intro", null);
-        nextStep();
+    function getService() {
+      if (services.mapillary && !_mapillary) {
+        _mapillary = services.mapillary;
+        _mapillary.event.on("imageChanged", throttledRedraw);
+        _mapillary.event.on("bearingChanged", function(e3) {
+          viewerCompassAngle = e3.bearing;
+          if (context.map().isTransformed()) return;
+          layer.selectAll(".viewfield-group.currentView").filter(function(d2) {
+            return d2.is_pano;
+          }).attr("transform", transform2);
+        });
+      } else if (!services.mapillary && _mapillary) {
+        _mapillary = null;
       }
+      return _mapillary;
     }
-    function clickTownHall() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var entity = context.hasEntity(hallId);
-      if (!entity)
-        return;
-      reveal(null, null, { duration: 0 });
-      context.map().centerZoomEase(entity.loc, 19, 500);
-      timeout2(function() {
-        var entity2 = context.hasEntity(hallId);
-        if (!entity2)
-          return;
-        var box = pointBox(entity2.loc, context);
-        var textId = context.lastPointerType() === "mouse" ? "click_townhall" : "tap_townhall";
-        reveal(box, helpHtml("intro.navigation." + textId));
-        context.map().on("move.intro drawn.intro", function() {
-          var entity3 = context.hasEntity(hallId);
-          if (!entity3)
-            return;
-          var box2 = pointBox(entity3.loc, context);
-          reveal(box2, helpHtml("intro.navigation." + textId), { duration: 0 });
-        });
-        context.on("enter.intro", function() {
-          if (isTownHallSelected())
-            continueTo(selectedTownHall);
-        });
-      }, 550);
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+    function editOn() {
+      layer.style("display", "block");
+    }
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function transform2(d2) {
+      let t2 = svgPointTransform(projection2)(d2);
+      if (d2.is_pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
+        t2 += " rotate(" + Math.floor(viewerCompassAngle) + ",0,0)";
+      } else if (d2.ca) {
+        t2 += " rotate(" + Math.floor(d2.ca) + ",0,0)";
       }
+      return t2;
     }
-    function selectedTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      var entity = context.hasEntity(hallId);
-      if (!entity)
-        return clickTownHall();
-      var box = pointBox(entity.loc, context);
-      var onClick = function() {
-        continueTo(editorTownHall);
-      };
-      reveal(
-        box,
-        helpHtml("intro.navigation.selected_townhall"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("move.intro drawn.intro", function() {
-        var entity2 = context.hasEntity(hallId);
-        if (!entity2)
-          return;
-        var box2 = pointBox(entity2.loc, context);
-        reveal(
-          box2,
-          helpHtml("intro.navigation.selected_townhall"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
+    function update() {
+      const z2 = ~~context.map().zoom();
+      const showViewfields = z2 >= minViewfieldZoom2;
+      const service = getService();
+      const image = service && service.getActiveImage();
+      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(image ? [image] : [], function(d2) {
+        return d2.id;
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
+      groups.exit().remove();
+      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group currentView highlighted");
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      const markers = groups.merge(groupsEnter).attr("transform", transform2).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z");
     }
-    function editorTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      var onClick = function() {
-        continueTo(presetTownHall);
-      };
-      reveal(
-        ".entity-editor-pane",
-        helpHtml("intro.navigation.editor_townhall"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.on("exit.intro", function() {
-        continueTo(clickTownHall);
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        nextStep();
+    function drawImages(selection2) {
+      const service = getService();
+      layer = selection2.selectAll(".layer-mapillary-position").data(service ? [0] : []);
+      layer.exit().remove();
+      const layerEnter = layer.enter().append("g").attr("class", "layer-mapillary-position");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (service && ~~context.map().zoom() >= minZoom5) {
+        editOn();
+        update();
+      } else {
+        editOff();
       }
     }
-    function presetTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      var entity = context.entity(context.selectedIDs()[0]);
-      var preset = _mainPresetIndex.match(entity, context.graph());
-      var onClick = function() {
-        continueTo(fieldsTownHall);
-      };
-      reveal(
-        ".entity-editor-pane .section-feature-type",
-        helpHtml("intro.navigation.preset_townhall", { preset: preset.name() }),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.on("exit.intro", function() {
-        continueTo(clickTownHall);
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        nextStep();
-      }
+    drawImages.enabled = function() {
+      update();
+      return this;
+    };
+    drawImages.supported = function() {
+      return !!getService();
+    };
+    drawImages.rendered = function(zoom) {
+      return zoom >= minZoom5;
+    };
+    init2();
+    return drawImages;
+  }
+
+  // modules/svg/mapillary_signs.js
+  function svgMapillarySigns(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    const minZoom5 = 12;
+    let layer = select_default2(null);
+    let _mapillary;
+    function init2() {
+      if (svgMapillarySigns.initialized) return;
+      svgMapillarySigns.enabled = false;
+      svgMapillarySigns.initialized = true;
     }
-    function fieldsTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      var onClick = function() {
-        continueTo(closeTownHall);
-      };
-      reveal(
-        ".entity-editor-pane .section-preset-fields",
-        helpHtml("intro.navigation.fields_townhall"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.on("exit.intro", function() {
-        continueTo(clickTownHall);
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(hallId)) {
-          continueTo(clickTownHall);
-        }
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        nextStep();
+    function getService() {
+      if (services.mapillary && !_mapillary) {
+        _mapillary = services.mapillary;
+        _mapillary.event.on("loadedSigns", throttledRedraw);
+      } else if (!services.mapillary && _mapillary) {
+        _mapillary = null;
       }
+      return _mapillary;
     }
-    function closeTownHall() {
-      if (!isTownHallSelected())
-        return clickTownHall();
-      var selector = ".entity-editor-pane button.close svg use";
-      var href = select_default2(selector).attr("href") || "#iD-icon-close";
-      reveal(
-        ".entity-editor-pane",
-        helpHtml("intro.navigation.close_townhall", { button: { html: icon(href, "inline") } })
-      );
-      context.on("exit.intro", function() {
-        continueTo(searchStreet);
-      });
-      context.history().on("change.intro", function() {
-        var selector2 = ".entity-editor-pane button.close svg use";
-        var href2 = select_default2(selector2).attr("href") || "#iD-icon-close";
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.navigation.close_townhall", { button: { html: icon(href2, "inline") } }),
-          { duration: 0 }
-        );
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
+    function showLayer() {
+      const service = getService();
+      if (!service) return;
+      service.loadSignResources(context);
+      editOn();
     }
-    function searchStreet() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var msec = transitionTime(springStreet, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
-      }
-      context.map().centerZoomEase(springStreet, 19, msec);
-      timeout2(function() {
-        reveal(
-          ".search-header input",
-          helpHtml("intro.navigation.search_street", { name: _t("intro.graph.name.spring-street") })
-        );
-        context.container().select(".search-header input").on("keyup.intro", checkSearchResult);
-      }, msec + 100);
+    function hideLayer() {
+      throttledRedraw.cancel();
+      editOff();
     }
-    function checkSearchResult() {
-      var first = context.container().select(".feature-list-item:nth-child(0n+2)");
-      var firstName = first.select(".entity-name");
-      var name = _t("intro.graph.name.spring-street");
-      if (!firstName.empty() && firstName.html() === name) {
-        reveal(
-          first.node(),
-          helpHtml("intro.navigation.choose_street", { name }),
-          { duration: 300 }
-        );
-        context.on("exit.intro", function() {
-          continueTo(selectedStreet);
-        });
-        context.container().select(".search-header input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
-      }
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.container().select(".search-header input").on("keydown.intro", null).on("keyup.intro", null);
-        nextStep();
-      }
+    function editOn() {
+      layer.style("display", "block");
     }
-    function selectedStreet() {
-      if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
-        return searchStreet();
-      }
-      var onClick = function() {
-        continueTo(editorStreet);
-      };
-      var entity = context.entity(springStreetEndId);
-      var box = pointBox(entity.loc, context);
-      box.height = 500;
-      reveal(
-        box,
-        helpHtml("intro.navigation.selected_street", { name: _t("intro.graph.name.spring-street") }),
-        { duration: 600, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      timeout2(function() {
-        context.map().on("move.intro drawn.intro", function() {
-          var entity2 = context.hasEntity(springStreetEndId);
-          if (!entity2)
-            return;
-          var box2 = pointBox(entity2.loc, context);
-          box2.height = 500;
-          reveal(
-            box2,
-            helpHtml("intro.navigation.selected_street", { name: _t("intro.graph.name.spring-street") }),
-            { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-          );
-        });
-      }, 600);
-      context.on("enter.intro", function(mode) {
-        if (!context.hasEntity(springStreetId)) {
-          return continueTo(searchStreet);
-        }
-        var ids = context.selectedIDs();
-        if (mode.id !== "select" || !ids.length || ids[0] !== springStreetId) {
-          context.enter(modeSelect(context, [springStreetId]));
-        }
-      });
-      context.history().on("change.intro", function() {
-        if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
-          timeout2(function() {
-            continueTo(searchStreet);
-          }, 300);
+    function editOff() {
+      layer.selectAll(".icon-sign").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, d2) {
+      const service = getService();
+      if (!service) return;
+      context.map().centerEase(d2.loc);
+      const selectedImageId = service.getActiveImage() && service.getActiveImage().id;
+      service.getDetections(d2.id).then((detections) => {
+        if (detections.length) {
+          const imageId = detections[0].image.id;
+          if (imageId === selectedImageId) {
+            service.highlightDetection(detections[0]).selectImage(context, imageId);
+          } else {
+            service.ensureViewerLoaded(context).then(function() {
+              service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
+            });
+          }
         }
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+    }
+    function filterData(detectedFeatures) {
+      var fromDate = context.photos().fromDate();
+      var toDate = context.photos().toDate();
+      if (fromDate) {
+        var fromTimestamp = new Date(fromDate).getTime();
+        detectedFeatures = detectedFeatures.filter(function(feature3) {
+          return new Date(feature3.last_seen_at).getTime() >= fromTimestamp;
+        });
+      }
+      if (toDate) {
+        var toTimestamp = new Date(toDate).getTime();
+        detectedFeatures = detectedFeatures.filter(function(feature3) {
+          return new Date(feature3.first_seen_at).getTime() <= toTimestamp;
+        });
       }
+      return detectedFeatures;
     }
-    function editorStreet() {
-      var selector = ".entity-editor-pane button.close svg use";
-      var href = select_default2(selector).attr("href") || "#iD-icon-close";
-      reveal(".entity-editor-pane", helpHtml("intro.navigation.street_different_fields") + "{br}" + helpHtml("intro.navigation.editor_street", {
-        button: { html: icon(href, "inline") },
-        field1: onewayField.title(),
-        field2: maxspeedField.title()
-      }));
-      context.on("exit.intro", function() {
-        continueTo(play);
+    function update() {
+      const service = getService();
+      let data = service ? service.signs(projection2) : [];
+      data = filterData(data);
+      const transform2 = svgPointTransform(projection2);
+      const signs = layer.selectAll(".icon-sign").data(data, function(d2) {
+        return d2.id;
       });
-      context.history().on("change.intro", function() {
-        var selector2 = ".entity-editor-pane button.close svg use";
-        var href2 = select_default2(selector2).attr("href") || "#iD-icon-close";
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.navigation.street_different_fields") + "{br}" + helpHtml("intro.navigation.editor_street", {
-            button: { html: icon(href2, "inline") },
-            field1: onewayField.title(),
-            field2: maxspeedField.title()
-          }),
-          { duration: 0 }
-        );
+      signs.exit().remove();
+      const enter = signs.enter().append("g").attr("class", "icon-sign icon-detected").on("click", click);
+      enter.append("use").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px").attr("xlink:href", function(d2) {
+        return "#" + d2.value;
       });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
+      enter.append("rect").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px");
+      signs.merge(enter).attr("transform", transform2);
     }
-    function play() {
-      dispatch10.call("done");
-      reveal(
-        ".ideditor",
-        helpHtml("intro.navigation.play", { next: _t("intro.points.title") }),
-        {
-          tooltipBox: ".intro-nav-wrap .chapter-point",
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            reveal(".ideditor");
-          }
+    function drawSigns(selection2) {
+      const enabled = svgMapillarySigns.enabled;
+      const service = getService();
+      layer = selection2.selectAll(".layer-mapillary-signs").data(service ? [0] : []);
+      layer.exit().remove();
+      layer = layer.enter().append("g").attr("class", "layer-mapillary-signs layer-mapillary-detections").style("display", enabled ? "block" : "none").merge(layer);
+      if (enabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          update();
+          service.loadSigns(projection2);
+          service.showSignDetections(true);
+        } else {
+          editOff();
         }
-      );
+      } else if (service) {
+        service.showSignDetections(false);
+      }
     }
-    chapter.enter = function() {
-      dragMap();
+    drawSigns.enabled = function(_2) {
+      if (!arguments.length) return svgMapillarySigns.enabled;
+      svgMapillarySigns.enabled = _2;
+      if (svgMapillarySigns.enabled) {
+        showLayer();
+        context.photos().on("change.mapillary_signs", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.mapillary_signs", null);
+      }
+      dispatch14.call("change");
+      return this;
     };
-    chapter.exit = function() {
-      timeouts.forEach(window.clearTimeout);
-      context.on("enter.intro exit.intro", null);
-      context.map().on("move.intro drawn.intro", null);
-      context.history().on("change.intro", null);
-      context.container().select(".inspector-wrap").on("wheel.intro", null);
-      context.container().select(".search-header input").on("keydown.intro keyup.intro", null);
+    drawSigns.supported = function() {
+      return !!getService();
     };
-    chapter.restart = function() {
-      chapter.exit();
-      chapter.enter();
+    drawSigns.rendered = function(zoom) {
+      return zoom >= minZoom5;
     };
-    return utilRebind(chapter, dispatch10, "on");
+    init2();
+    return drawSigns;
   }
 
-  // modules/ui/intro/point.js
-  function uiIntroPoint(context, reveal) {
-    var dispatch10 = dispatch_default("done");
-    var timeouts = [];
-    var intersection = [-85.63279, 41.94394];
-    var building = [-85.632422, 41.944045];
-    var cafePreset = _mainPresetIndex.item("amenity/cafe");
-    var _pointID = null;
-    var chapter = {
-      title: "intro.points.title"
-    };
-    function timeout2(f2, t) {
-      timeouts.push(window.setTimeout(f2, t));
+  // modules/svg/mapillary_map_features.js
+  function svgMapillaryMapFeatures(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    const minZoom5 = 12;
+    let layer = select_default2(null);
+    let _mapillary;
+    function init2() {
+      if (svgMapillaryMapFeatures.initialized) return;
+      svgMapillaryMapFeatures.enabled = false;
+      svgMapillaryMapFeatures.initialized = true;
     }
-    function eventCancel(d3_event) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
+    function getService() {
+      if (services.mapillary && !_mapillary) {
+        _mapillary = services.mapillary;
+        _mapillary.event.on("loadedMapFeatures", throttledRedraw);
+      } else if (!services.mapillary && _mapillary) {
+        _mapillary = null;
+      }
+      return _mapillary;
     }
-    function addPoint() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var msec = transitionTime(intersection, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
+    function showLayer() {
+      const service = getService();
+      if (!service) return;
+      service.loadObjectResources(context);
+      editOn();
+    }
+    function hideLayer() {
+      throttledRedraw.cancel();
+      editOff();
+    }
+    function editOn() {
+      layer.style("display", "block");
+    }
+    function editOff() {
+      layer.selectAll(".icon-map-feature").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, d2) {
+      const service = getService();
+      if (!service) return;
+      context.map().centerEase(d2.loc);
+      const selectedImageId = service.getActiveImage() && service.getActiveImage().id;
+      service.getDetections(d2.id).then((detections) => {
+        if (detections.length) {
+          const imageId = detections[0].image.id;
+          if (imageId === selectedImageId) {
+            service.highlightDetection(detections[0]).selectImage(context, imageId);
+          } else {
+            service.ensureViewerLoaded(context).then(function() {
+              service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
+            });
+          }
+        }
+      });
+    }
+    function filterData(detectedFeatures) {
+      const fromDate = context.photos().fromDate();
+      const toDate = context.photos().toDate();
+      if (fromDate) {
+        detectedFeatures = detectedFeatures.filter(function(feature3) {
+          return new Date(feature3.last_seen_at).getTime() >= new Date(fromDate).getTime();
+        });
       }
-      context.map().centerZoomEase(intersection, 19, msec);
-      timeout2(function() {
-        var tooltip = reveal(
-          "button.add-point",
-          helpHtml("intro.points.points_info") + "{br}" + helpHtml("intro.points.add_point")
-        );
-        _pointID = null;
-        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-points");
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-point")
-            return;
-          continueTo(placePoint);
+      if (toDate) {
+        detectedFeatures = detectedFeatures.filter(function(feature3) {
+          return new Date(feature3.first_seen_at).getTime() <= new Date(toDate).getTime();
         });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        nextStep();
       }
+      return detectedFeatures;
     }
-    function placePoint() {
-      if (context.mode().id !== "add-point") {
-        return chapter.restart();
-      }
-      var pointBox2 = pad(building, 150, context);
-      var textId = context.lastPointerType() === "mouse" ? "place_point" : "place_point_touch";
-      reveal(pointBox2, helpHtml("intro.points." + textId));
-      context.map().on("move.intro drawn.intro", function() {
-        pointBox2 = pad(building, 150, context);
-        reveal(pointBox2, helpHtml("intro.points." + textId), { duration: 0 });
+    function update() {
+      const service = getService();
+      let data = service ? service.mapFeatures(projection2) : [];
+      data = filterData(data);
+      const transform2 = svgPointTransform(projection2);
+      const mapFeatures = layer.selectAll(".icon-map-feature").data(data, function(d2) {
+        return d2.id;
       });
-      context.on("enter.intro", function(mode) {
-        if (mode.id !== "select")
-          return chapter.restart();
-        _pointID = context.mode().selectedIDs()[0];
-        continueTo(searchPreset);
+      mapFeatures.exit().remove();
+      const enter = mapFeatures.enter().append("g").attr("class", "icon-map-feature icon-detected").on("click", click);
+      enter.append("title").text(function(d2) {
+        var id2 = d2.value.replace(/--/g, ".").replace(/-/g, "_");
+        return _t("mapillary_map_features." + id2);
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
+      enter.append("use").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px").attr("xlink:href", function(d2) {
+        if (d2.value === "object--billboard") {
+          return "#object--sign--advertisement";
+        }
+        return "#" + d2.value;
+      });
+      enter.append("rect").attr("width", "24px").attr("height", "24px").attr("x", "-12px").attr("y", "-12px");
+      mapFeatures.merge(enter).attr("transform", transform2);
+    }
+    function drawMapFeatures(selection2) {
+      const enabled = svgMapillaryMapFeatures.enabled;
+      const service = getService();
+      layer = selection2.selectAll(".layer-mapillary-map-features").data(service ? [0] : []);
+      layer.exit().remove();
+      layer = layer.enter().append("g").attr("class", "layer-mapillary-map-features layer-mapillary-detections").style("display", enabled ? "block" : "none").merge(layer);
+      if (enabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          update();
+          service.loadMapFeatures(projection2);
+          service.showFeatureDetections(true);
+        } else {
+          editOff();
+        }
+      } else if (service) {
+        service.showFeatureDetections(false);
       }
     }
-    function searchPreset() {
-      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
-        return addPoint();
-      }
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
-      reveal(
-        ".preset-search-input",
-        helpHtml("intro.points.search_cafe", { preset: cafePreset.name() })
-      );
-      context.on("enter.intro", function(mode) {
-        if (!_pointID || !context.hasEntity(_pointID)) {
-          return continueTo(addPoint);
-        }
-        var ids = context.selectedIDs();
-        if (mode.id !== "select" || !ids.length || ids[0] !== _pointID) {
-          context.enter(modeSelect(context, [_pointID]));
-          context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-          context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
-          reveal(
-            ".preset-search-input",
-            helpHtml("intro.points.search_cafe", { preset: cafePreset.name() })
-          );
-          context.history().on("change.intro", null);
-        }
-      });
-      function checkPresetSearch() {
-        var first = context.container().select(".preset-list-item:first-child");
-        if (first.classed("preset-amenity-cafe")) {
-          context.container().select(".preset-search-input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
-          reveal(
-            first.select(".preset-list-button").node(),
-            helpHtml("intro.points.choose_cafe", { preset: cafePreset.name() }),
-            { duration: 300 }
-          );
-          context.history().on("change.intro", function() {
-            continueTo(aboutFeatureEditor);
-          });
-        }
-      }
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
-        nextStep();
+    drawMapFeatures.enabled = function(_2) {
+      if (!arguments.length) return svgMapillaryMapFeatures.enabled;
+      svgMapillaryMapFeatures.enabled = _2;
+      if (svgMapillaryMapFeatures.enabled) {
+        showLayer();
+        context.photos().on("change.mapillary_map_features", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.mapillary_map_features", null);
       }
+      dispatch14.call("change");
+      return this;
+    };
+    drawMapFeatures.supported = function() {
+      return !!getService();
+    };
+    drawMapFeatures.rendered = function(zoom) {
+      return zoom >= minZoom5;
+    };
+    init2();
+    return drawMapFeatures;
+  }
+
+  // modules/svg/kartaview_images.js
+  function svgKartaviewImages(projection2, context, dispatch14) {
+    var throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    var minZoom5 = 12;
+    var minMarkerZoom = 16;
+    var minViewfieldZoom2 = 18;
+    var layer = select_default2(null);
+    var _kartaview;
+    function init2() {
+      if (svgKartaviewImages.initialized) return;
+      svgKartaviewImages.enabled = false;
+      svgKartaviewImages.initialized = true;
     }
-    function aboutFeatureEditor() {
-      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
-        return addPoint();
-      }
-      timeout2(function() {
-        reveal(".entity-editor-pane", helpHtml("intro.points.feature_editor"), {
-          tooltipClass: "intro-points-describe",
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            continueTo(addName);
-          }
-        });
-      }, 400);
-      context.on("exit.intro", function() {
-        continueTo(reselectPoint);
-      });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
+    function getService() {
+      if (services.kartaview && !_kartaview) {
+        _kartaview = services.kartaview;
+        _kartaview.event.on("loadedImages", throttledRedraw);
+      } else if (!services.kartaview && _kartaview) {
+        _kartaview = null;
       }
+      return _kartaview;
     }
-    function addName() {
-      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
-        return addPoint();
-      }
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      var addNameString = helpHtml("intro.points.fields_info") + "{br}" + helpHtml("intro.points.add_name");
-      timeout2(function() {
-        var entity = context.entity(_pointID);
-        if (entity.tags.name) {
-          var tooltip = reveal(".entity-editor-pane", addNameString, {
-            tooltipClass: "intro-points-describe",
-            buttonText: _t.html("intro.ok"),
-            buttonCallback: function() {
-              continueTo(addCloseEditor);
-            }
-          });
-          tooltip.select(".instruction").style("display", "none");
-        } else {
-          reveal(
-            ".entity-editor-pane",
-            addNameString,
-            { tooltipClass: "intro-points-describe" }
-          );
-        }
-      }, 400);
-      context.history().on("change.intro", function() {
-        continueTo(addCloseEditor);
+    function showLayer() {
+      var service = getService();
+      if (!service) return;
+      editOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
       });
-      context.on("exit.intro", function() {
-        continueTo(reselectPoint);
+    }
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
+    }
+    function editOn() {
+      layer.style("display", "block");
+    }
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, d2) {
+      var service = getService();
+      if (!service) return;
+      service.ensureViewerLoaded(context).then(function() {
+        service.selectImage(context, d2.key).showViewer(context);
       });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+      context.map().centerEase(d2.loc);
+    }
+    function mouseover(d3_event, d2) {
+      var service = getService();
+      if (service) service.setStyles(context, d2);
+    }
+    function mouseout() {
+      var service = getService();
+      if (service) service.setStyles(context, null);
+    }
+    function transform2(d2) {
+      var t2 = svgPointTransform(projection2)(d2);
+      if (d2.ca) {
+        t2 += " rotate(" + Math.floor(d2.ca) + ",0,0)";
       }
+      return t2;
     }
-    function addCloseEditor() {
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      var selector = ".entity-editor-pane button.close svg use";
-      var href = select_default2(selector).attr("href") || "#iD-icon-close";
-      context.on("exit.intro", function() {
-        continueTo(reselectPoint);
-      });
-      reveal(
-        ".entity-editor-pane",
-        helpHtml("intro.points.add_close", { button: { html: icon(href, "inline") } })
-      );
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
+    function filterImages(images) {
+      var fromDate = context.photos().fromDate();
+      var toDate = context.photos().toDate();
+      var usernames = context.photos().usernames();
+      if (fromDate) {
+        var fromTimestamp = new Date(fromDate).getTime();
+        images = images.filter(function(item) {
+          return new Date(item.captured_at).getTime() >= fromTimestamp;
+        });
+      }
+      if (toDate) {
+        var toTimestamp = new Date(toDate).getTime();
+        images = images.filter(function(item) {
+          return new Date(item.captured_at).getTime() <= toTimestamp;
+        });
+      }
+      if (usernames) {
+        images = images.filter(function(item) {
+          return usernames.indexOf(item.captured_by) !== -1;
+        });
       }
+      return images;
     }
-    function reselectPoint() {
-      if (!_pointID)
-        return chapter.restart();
-      var entity = context.hasEntity(_pointID);
-      if (!entity)
-        return chapter.restart();
-      var oldPreset = _mainPresetIndex.match(entity, context.graph());
-      context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
-      context.enter(modeBrowse(context));
-      var msec = transitionTime(entity.loc, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
+    function filterSequences(sequences) {
+      var fromDate = context.photos().fromDate();
+      var toDate = context.photos().toDate();
+      var usernames = context.photos().usernames();
+      if (fromDate) {
+        var fromTimestamp = new Date(fromDate).getTime();
+        sequences = sequences.filter(function(image) {
+          return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
+        });
       }
-      context.map().centerEase(entity.loc, msec);
-      timeout2(function() {
-        var box = pointBox(entity.loc, context);
-        reveal(box, helpHtml("intro.points.reselect"), { duration: 600 });
-        timeout2(function() {
-          context.map().on("move.intro drawn.intro", function() {
-            var entity2 = context.hasEntity(_pointID);
-            if (!entity2)
-              return chapter.restart();
-            var box2 = pointBox(entity2.loc, context);
-            reveal(box2, helpHtml("intro.points.reselect"), { duration: 0 });
-          });
-        }, 600);
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "select")
-            return;
-          continueTo(updatePoint);
+      if (toDate) {
+        var toTimestamp = new Date(toDate).getTime();
+        sequences = sequences.filter(function(image) {
+          return new Date(image.properties.captured_at).getTime() <= toTimestamp;
+        });
+      }
+      if (usernames) {
+        sequences = sequences.filter(function(image) {
+          return usernames.indexOf(image.properties.captured_by) !== -1;
         });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
       }
+      return sequences;
     }
-    function updatePoint() {
-      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
-        return continueTo(reselectPoint);
+    function update() {
+      var viewer = context.container().select(".photoviewer");
+      var selected = viewer.empty() ? void 0 : viewer.datum();
+      var z2 = ~~context.map().zoom();
+      var showMarkers = z2 >= minMarkerZoom;
+      var showViewfields = z2 >= minViewfieldZoom2;
+      var service = getService();
+      var sequences = [];
+      var images = [];
+      if (context.photos().showsFlat()) {
+        sequences = service ? service.sequences(projection2) : [];
+        images = service && showMarkers ? service.images(projection2) : [];
+        sequences = filterSequences(sequences);
+        images = filterImages(images);
       }
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      context.on("exit.intro", function() {
-        continueTo(reselectPoint);
+      var traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d2) {
+        return d2.properties.key;
       });
-      context.history().on("change.intro", function() {
-        continueTo(updateCloseEditor);
+      traces.exit().remove();
+      traces = traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
+      var groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, function(d2) {
+        return d2.key;
       });
-      timeout2(function() {
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.points.update"),
-          { tooltipClass: "intro-points-describe" }
-        );
-      }, 400);
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+      groups.exit().remove();
+      var groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      var markers = groups.merge(groupsEnter).sort(function(a2, b2) {
+        return a2 === selected ? 1 : b2 === selected ? -1 : b2.loc[1] - a2.loc[1];
+      }).attr("transform", transform2).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      var viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z");
+    }
+    function drawImages(selection2) {
+      var enabled = svgKartaviewImages.enabled, service = getService();
+      layer = selection2.selectAll(".layer-kartaview").data(service ? [0] : []);
+      layer.exit().remove();
+      var layerEnter = layer.enter().append("g").attr("class", "layer-kartaview").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "sequences");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          update();
+          service.loadImages(projection2);
+        } else {
+          editOff();
+        }
       }
     }
-    function updateCloseEditor() {
-      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
-        return continueTo(reselectPoint);
+    drawImages.enabled = function(_2) {
+      if (!arguments.length) return svgKartaviewImages.enabled;
+      svgKartaviewImages.enabled = _2;
+      if (svgKartaviewImages.enabled) {
+        showLayer();
+        context.photos().on("change.kartaview_images", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.kartaview_images", null);
       }
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      context.on("exit.intro", function() {
-        continueTo(rightClickPoint);
-      });
-      timeout2(function() {
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.points.update_close", { button: { html: icon("#iD-icon-close", "inline") } })
-        );
-      }, 500);
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
+      dispatch14.call("change");
+      return this;
+    };
+    drawImages.supported = function() {
+      return !!getService();
+    };
+    drawImages.rendered = function(zoom) {
+      return zoom >= minZoom5;
+    };
+    init2();
+    return drawImages;
+  }
+
+  // modules/svg/mapilio_images.js
+  function svgMapilioImages(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    const minZoom5 = 12;
+    let layer = select_default2(null);
+    let _mapilio;
+    const viewFieldZoomLevel = 18;
+    function init2() {
+      if (svgMapilioImages.initialized) return;
+      svgMapilioImages.enabled = false;
+      svgMapilioImages.initialized = true;
+    }
+    function getService() {
+      if (services.mapilio && !_mapilio) {
+        _mapilio = services.mapilio;
+        _mapilio.event.on("loadedImages", throttledRedraw);
+      } else if (!services.mapilio && _mapilio) {
+        _mapilio = null;
       }
+      return _mapilio;
     }
-    function rightClickPoint() {
-      if (!_pointID)
-        return chapter.restart();
-      var entity = context.hasEntity(_pointID);
-      if (!entity)
-        return chapter.restart();
-      context.enter(modeBrowse(context));
-      var box = pointBox(entity.loc, context);
-      var textId = context.lastPointerType() === "mouse" ? "rightclick" : "edit_menu_touch";
-      reveal(box, helpHtml("intro.points." + textId), { duration: 600 });
-      timeout2(function() {
-        context.map().on("move.intro", function() {
-          var entity2 = context.hasEntity(_pointID);
-          if (!entity2)
-            return chapter.restart();
-          var box2 = pointBox(entity2.loc, context);
-          reveal(box2, helpHtml("intro.points." + textId), { duration: 0 });
-        });
-      }, 600);
-      context.on("enter.intro", function(mode) {
-        if (mode.id !== "select")
-          return;
-        var ids = context.selectedIDs();
-        if (ids.length !== 1 || ids[0] !== _pointID)
-          return;
-        timeout2(function() {
-          var node = selectMenuItem(context, "delete").node();
-          if (!node)
-            return;
-          continueTo(enterDelete);
-        }, 50);
+    function showLayer() {
+      const service = getService();
+      if (!service) return;
+      editOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
       });
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.map().on("move.intro", null);
-        nextStep();
-      }
     }
-    function enterDelete() {
-      if (!_pointID)
-        return chapter.restart();
-      var entity = context.hasEntity(_pointID);
-      if (!entity)
-        return chapter.restart();
-      var node = selectMenuItem(context, "delete").node();
-      if (!node) {
-        return continueTo(rightClickPoint);
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
+    }
+    function transform2(d2) {
+      let t2 = svgPointTransform(projection2)(d2);
+      if (d2.heading) {
+        t2 += " rotate(" + Math.floor(d2.heading) + ",0,0)";
       }
-      reveal(
-        ".edit-menu",
-        helpHtml("intro.points.delete"),
-        { padding: 50 }
-      );
-      timeout2(function() {
-        context.map().on("move.intro", function() {
-          reveal(
-            ".edit-menu",
-            helpHtml("intro.points.delete"),
-            { duration: 0, padding: 50 }
-          );
-        });
-      }, 300);
-      context.on("exit.intro", function() {
-        if (!_pointID)
-          return chapter.restart();
-        var entity2 = context.hasEntity(_pointID);
-        if (entity2)
-          return continueTo(rightClickPoint);
-      });
-      context.history().on("change.intro", function(changed) {
-        if (changed.deleted().length) {
-          continueTo(undo);
-        }
+      return t2;
+    }
+    function editOn() {
+      layer.style("display", "block");
+    }
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, image) {
+      const service = getService();
+      if (!service) return;
+      service.ensureViewerLoaded(context, image.id).then(function() {
+        service.selectImage(context, image.id).showViewer(context);
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro", null);
-        context.history().on("change.intro", null);
-        context.on("exit.intro", null);
-        nextStep();
-      }
+      context.map().centerEase(image.loc);
     }
-    function undo() {
-      context.history().on("change.intro", function() {
-        continueTo(play);
+    function mouseover(d3_event, image) {
+      const service = getService();
+      if (service) service.setStyles(context, image);
+    }
+    function mouseout() {
+      const service = getService();
+      if (service) service.setStyles(context, null);
+    }
+    function update() {
+      const z2 = ~~context.map().zoom();
+      const showViewfields = z2 >= viewFieldZoomLevel;
+      const service = getService();
+      let sequences = service ? service.sequences(projection2) : [];
+      let images = service ? service.images(projection2) : [];
+      let traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d2) {
+        return d2.properties.id;
       });
-      reveal(
-        ".top-toolbar button.undo-button",
-        helpHtml("intro.points.undo")
-      );
-      function continueTo(nextStep) {
-        context.history().on("change.intro", null);
-        nextStep();
+      traces.exit().remove();
+      traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
+      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, function(d2) {
+        return d2.id;
+      });
+      groups.exit().remove();
+      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      const markers = groups.merge(groupsEnter).sort(function(a2, b2) {
+        return b2.loc[1] - a2.loc[1];
+      }).attr("transform", transform2).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
+      function viewfieldPath() {
+        if (this.parentNode.__data__.isPano) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
       }
     }
-    function play() {
-      dispatch10.call("done");
-      reveal(
-        ".ideditor",
-        helpHtml("intro.points.play", { next: _t("intro.areas.title") }),
-        {
-          tooltipBox: ".intro-nav-wrap .chapter-area",
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            reveal(".ideditor");
-          }
+    function drawImages(selection2) {
+      const enabled = svgMapilioImages.enabled;
+      const service = getService();
+      layer = selection2.selectAll(".layer-mapilio").data(service ? [0] : []);
+      layer.exit().remove();
+      const layerEnter = layer.enter().append("g").attr("class", "layer-mapilio").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "sequences");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          update();
+          service.loadImages(projection2);
+          service.loadLines(projection2);
+        } else {
+          editOff();
         }
-      );
+      }
     }
-    chapter.enter = function() {
-      addPoint();
+    drawImages.enabled = function(_2) {
+      if (!arguments.length) return svgMapilioImages.enabled;
+      svgMapilioImages.enabled = _2;
+      if (svgMapilioImages.enabled) {
+        showLayer();
+        context.photos().on("change.mapilio_images", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.mapilio_images", null);
+      }
+      dispatch14.call("change");
+      return this;
     };
-    chapter.exit = function() {
-      timeouts.forEach(window.clearTimeout);
-      context.on("enter.intro exit.intro", null);
-      context.map().on("move.intro drawn.intro", null);
-      context.history().on("change.intro", null);
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
+    drawImages.supported = function() {
+      return !!getService();
     };
-    chapter.restart = function() {
-      chapter.exit();
-      chapter.enter();
+    drawImages.rendered = function(zoom) {
+      return zoom >= minZoom5;
     };
-    return utilRebind(chapter, dispatch10, "on");
+    init2();
+    return drawImages;
   }
 
-  // modules/ui/intro/area.js
-  function uiIntroArea(context, reveal) {
-    var dispatch10 = dispatch_default("done");
-    var playground = [-85.63552, 41.94159];
-    var playgroundPreset = _mainPresetIndex.item("leisure/playground");
-    var nameField = _mainPresetIndex.field("name");
-    var descriptionField = _mainPresetIndex.field("description");
-    var timeouts = [];
-    var _areaID;
-    var chapter = {
-      title: "intro.areas.title"
-    };
-    function timeout2(f2, t) {
-      timeouts.push(window.setTimeout(f2, t));
-    }
-    function eventCancel(d3_event) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
-    }
-    function revealPlayground(center, text2, options2) {
-      var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
-      var box = pad(center, padding, context);
-      reveal(box, text2, options2);
+  // modules/svg/panoramax_images.js
+  function svgPanoramaxImages(projection2, context, dispatch14) {
+    const throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    const imageMinZoom2 = 15;
+    const lineMinZoom2 = 10;
+    const viewFieldZoomLevel = 18;
+    let layer = select_default2(null);
+    let _panoramax;
+    let _viewerYaw = 0;
+    let _selectedSequence;
+    let _activeUsernameFilter;
+    let _activeIds;
+    function init2() {
+      if (svgPanoramaxImages.initialized) return;
+      svgPanoramaxImages.enabled = false;
+      svgPanoramaxImages.initialized = true;
     }
-    function addArea() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      _areaID = null;
-      var msec = transitionTime(playground, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
-      }
-      context.map().centerZoomEase(playground, 19, msec);
-      timeout2(function() {
-        var tooltip = reveal(
-          "button.add-area",
-          helpHtml("intro.areas.add_playground")
-        );
-        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-areas");
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-area")
-            return;
-          continueTo(startPlayground);
-        });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        nextStep();
-      }
-    }
-    function startPlayground() {
-      if (context.mode().id !== "add-area") {
-        return chapter.restart();
-      }
-      _areaID = null;
-      context.map().zoomEase(19.5, 500);
-      timeout2(function() {
-        var textId = context.lastPointerType() === "mouse" ? "starting_node_click" : "starting_node_tap";
-        var startDrawString = helpHtml("intro.areas.start_playground") + helpHtml("intro.areas." + textId);
-        revealPlayground(
-          playground,
-          startDrawString,
-          { duration: 250 }
-        );
-        timeout2(function() {
-          context.map().on("move.intro drawn.intro", function() {
-            revealPlayground(
-              playground,
-              startDrawString,
-              { duration: 0 }
-            );
-          });
-          context.on("enter.intro", function(mode) {
-            if (mode.id !== "draw-area")
-              return chapter.restart();
-            continueTo(continuePlayground);
-          });
-        }, 250);
-      }, 550);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
+    function getService() {
+      if (services.panoramax && !_panoramax) {
+        _panoramax = services.panoramax;
+        _panoramax.event.on("viewerChanged", viewerChanged).on("loadedLines", throttledRedraw).on("loadedImages", throttledRedraw);
+      } else if (!services.panoramax && _panoramax) {
+        _panoramax = null;
       }
+      return _panoramax;
     }
-    function continuePlayground() {
-      if (context.mode().id !== "draw-area") {
-        return chapter.restart();
-      }
-      _areaID = null;
-      revealPlayground(
-        playground,
-        helpHtml("intro.areas.continue_playground"),
-        { duration: 250 }
-      );
-      timeout2(function() {
-        context.map().on("move.intro drawn.intro", function() {
-          revealPlayground(
-            playground,
-            helpHtml("intro.areas.continue_playground"),
-            { duration: 0 }
-          );
+    async function filterImages(images) {
+      const showsPano = context.photos().showsPanoramic();
+      const showsFlat = context.photos().showsFlat();
+      const fromDate = context.photos().fromDate();
+      const toDate = context.photos().toDate();
+      const username = context.photos().usernames();
+      const service = getService();
+      if (!showsPano || !showsFlat) {
+        images = images.filter(function(image) {
+          if (image.isPano) return showsPano;
+          return showsFlat;
         });
-      }, 250);
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "draw-area") {
-          var entity = context.hasEntity(context.selectedIDs()[0]);
-          if (entity && entity.nodes.length >= 6) {
-            return continueTo(finishPlayground);
-          } else {
-            return;
-          }
-        } else if (mode.id === "select") {
-          _areaID = context.selectedIDs()[0];
-          return continueTo(searchPresets);
-        } else {
-          return chapter.restart();
-        }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
       }
-    }
-    function finishPlayground() {
-      if (context.mode().id !== "draw-area") {
-        return chapter.restart();
-      }
-      _areaID = null;
-      var finishString = helpHtml("intro.areas.finish_area_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.areas.finish_playground");
-      revealPlayground(
-        playground,
-        finishString,
-        { duration: 250 }
-      );
-      timeout2(function() {
-        context.map().on("move.intro drawn.intro", function() {
-          revealPlayground(
-            playground,
-            finishString,
-            { duration: 0 }
-          );
+      if (fromDate) {
+        images = images.filter(function(image) {
+          return new Date(image.capture_time).getTime() >= new Date(fromDate).getTime();
         });
-      }, 250);
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "draw-area") {
-          return;
-        } else if (mode.id === "select") {
-          _areaID = context.selectedIDs()[0];
-          return continueTo(searchPresets);
-        } else {
-          return chapter.restart();
-        }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
-      }
-    }
-    function searchPresets() {
-      if (!_areaID || !context.hasEntity(_areaID)) {
-        return addArea();
       }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
-        context.enter(modeSelect(context, [_areaID]));
+      if (toDate) {
+        images = images.filter(function(image) {
+          return new Date(image.capture_time).getTime() <= new Date(toDate).getTime();
+        });
       }
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      timeout2(function() {
-        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
-        context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
-        reveal(
-          ".preset-search-input",
-          helpHtml("intro.areas.search_playground", { preset: playgroundPreset.name() })
-        );
-      }, 400);
-      context.on("enter.intro", function(mode) {
-        if (!_areaID || !context.hasEntity(_areaID)) {
-          return continueTo(addArea);
-        }
-        var ids2 = context.selectedIDs();
-        if (mode.id !== "select" || !ids2.length || ids2[0] !== _areaID) {
-          context.enter(modeSelect(context, [_areaID]));
-          context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
-          context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-          context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
-          reveal(
-            ".preset-search-input",
-            helpHtml("intro.areas.search_playground", { preset: playgroundPreset.name() })
-          );
-          context.history().on("change.intro", null);
-        }
-      });
-      function checkPresetSearch() {
-        var first = context.container().select(".preset-list-item:first-child");
-        if (first.classed("preset-leisure-playground")) {
-          reveal(
-            first.select(".preset-list-button").node(),
-            helpHtml("intro.areas.choose_playground", { preset: playgroundPreset.name() }),
-            { duration: 300 }
-          );
-          context.container().select(".preset-search-input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
-          context.history().on("change.intro", function() {
-            continueTo(clickAddField);
+      if (username && service) {
+        if (_activeUsernameFilter !== username) {
+          _activeUsernameFilter = username;
+          const tempIds = await service.getUserIds(username);
+          _activeIds = {};
+          tempIds.forEach((id2) => {
+            _activeIds[id2] = true;
           });
         }
+        images = images.filter(function(image) {
+          return _activeIds[image.account_id];
+        });
       }
-      function continueTo(nextStep) {
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.on("enter.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
-        nextStep();
-      }
+      return images;
     }
-    function clickAddField() {
-      if (!_areaID || !context.hasEntity(_areaID)) {
-        return addArea();
+    async function filterSequences(sequences) {
+      const showsPano = context.photos().showsPanoramic();
+      const showsFlat = context.photos().showsFlat();
+      const fromDate = context.photos().fromDate();
+      const toDate = context.photos().toDate();
+      const username = context.photos().usernames();
+      const service = getService();
+      if (!showsPano || !showsFlat) {
+        sequences = sequences.filter(function(sequence) {
+          if (sequence.properties.type === "equirectangular") return showsPano;
+          return showsFlat;
+        });
       }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
-        return searchPresets();
+      if (fromDate) {
+        sequences = sequences.filter(function(sequence) {
+          return new Date(sequence.properties.date).getTime() >= new Date(fromDate).getTime().toString();
+        });
       }
-      if (!context.container().select(".form-field-description").empty()) {
-        return continueTo(describePlayground);
+      if (toDate) {
+        sequences = sequences.filter(function(sequence) {
+          return new Date(sequence.properties.date).getTime() <= new Date(toDate).getTime().toString();
+        });
       }
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      timeout2(function() {
-        context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-        var entity = context.entity(_areaID);
-        if (entity.tags.description) {
-          return continueTo(play);
-        }
-        var box = context.container().select(".more-fields").node().getBoundingClientRect();
-        if (box.top > 300) {
-          var pane = context.container().select(".entity-editor-pane .inspector-body");
-          var start2 = pane.node().scrollTop;
-          var end = start2 + (box.top - 300);
-          pane.transition().duration(250).tween("scroll.inspector", function() {
-            var node = this;
-            var i2 = number_default(start2, end);
-            return function(t) {
-              node.scrollTop = i2(t);
-            };
+      if (username && service) {
+        if (_activeUsernameFilter !== username) {
+          _activeUsernameFilter = username;
+          const tempIds = await service.getUserIds(username);
+          _activeIds = {};
+          tempIds.forEach((id2) => {
+            _activeIds[id2] = true;
           });
         }
-        timeout2(function() {
-          reveal(
-            ".more-fields .combobox-input",
-            helpHtml("intro.areas.add_field", {
-              name: nameField.title(),
-              description: descriptionField.title()
-            }),
-            { duration: 300 }
-          );
-          context.container().select(".more-fields .combobox-input").on("click.intro", function() {
-            var watcher;
-            watcher = window.setInterval(function() {
-              if (!context.container().select("div.combobox").empty()) {
-                window.clearInterval(watcher);
-                continueTo(chooseDescriptionField);
-              }
-            }, 300);
-          });
-        }, 300);
-      }, 400);
-      context.on("exit.intro", function() {
-        return continueTo(searchPresets);
-      });
-      function continueTo(nextStep) {
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.container().select(".more-fields .combobox-input").on("click.intro", null);
-        context.on("exit.intro", null);
-        nextStep();
+        sequences = sequences.filter(function(sequence) {
+          return _activeIds[sequence.properties.account_id];
+        });
       }
+      return sequences;
     }
-    function chooseDescriptionField() {
-      if (!_areaID || !context.hasEntity(_areaID)) {
-        return addArea();
-      }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
-        return searchPresets();
-      }
-      if (!context.container().select(".form-field-description").empty()) {
-        return continueTo(describePlayground);
-      }
-      if (context.container().select("div.combobox").empty()) {
-        return continueTo(clickAddField);
-      }
-      var watcher;
-      watcher = window.setInterval(function() {
-        if (context.container().select("div.combobox").empty()) {
-          window.clearInterval(watcher);
-          timeout2(function() {
-            if (context.container().select(".form-field-description").empty()) {
-              continueTo(retryChooseDescription);
-            } else {
-              continueTo(describePlayground);
-            }
-          }, 300);
-        }
-      }, 300);
-      reveal(
-        "div.combobox",
-        helpHtml("intro.areas.choose_field", { field: descriptionField.title() }),
-        { duration: 300 }
-      );
-      context.on("exit.intro", function() {
-        return continueTo(searchPresets);
+    function showLayer() {
+      const service = getService();
+      if (!service) return;
+      editOn();
+      layer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end", function() {
+        dispatch14.call("change");
       });
-      function continueTo(nextStep) {
-        if (watcher)
-          window.clearInterval(watcher);
-        context.on("exit.intro", null);
-        nextStep();
-      }
     }
-    function describePlayground() {
-      if (!_areaID || !context.hasEntity(_areaID)) {
-        return addArea();
+    function hideLayer() {
+      throttledRedraw.cancel();
+      layer.transition().duration(250).style("opacity", 0).on("end", editOff);
+    }
+    function transform2(d2, selectedImageId) {
+      let t2 = svgPointTransform(projection2)(d2);
+      let rot = d2.heading;
+      if (d2.id === selectedImageId) {
+        rot += _viewerYaw;
       }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
-        return searchPresets();
+      if (rot) {
+        t2 += " rotate(" + Math.floor(rot) + ",0,0)";
       }
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      if (context.container().select(".form-field-description").empty()) {
-        return continueTo(retryChooseDescription);
+      return t2;
+    }
+    function editOn() {
+      layer.style("display", "block");
+    }
+    function editOff() {
+      layer.selectAll(".viewfield-group").remove();
+      layer.style("display", "none");
+    }
+    function click(d3_event, image) {
+      const service = getService();
+      if (!service) return;
+      if (image.sequence_id !== _selectedSequence) {
+        _viewerYaw = 0;
       }
-      context.on("exit.intro", function() {
-        continueTo(play);
+      _selectedSequence = image.sequence_id;
+      service.ensureViewerLoaded(context).then(function() {
+        service.selectImage(context, image.id).showViewer(context);
       });
-      reveal(
-        ".entity-editor-pane",
-        helpHtml("intro.areas.describe_playground", { button: { html: icon("#iD-icon-close", "inline") } }),
-        { duration: 300 }
-      );
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
-      }
+      context.map().centerEase(image.loc);
     }
-    function retryChooseDescription() {
-      if (!_areaID || !context.hasEntity(_areaID)) {
-        return addArea();
-      }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
-        return searchPresets();
-      }
-      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
-      reveal(
-        ".entity-editor-pane",
-        helpHtml("intro.areas.retry_add_field", { field: descriptionField.title() }),
-        {
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            continueTo(clickAddField);
-          }
-        }
-      );
-      context.on("exit.intro", function() {
-        return continueTo(searchPresets);
+    function mouseover(d3_event, image) {
+      const service = getService();
+      if (service) service.setStyles(context, image);
+    }
+    function mouseout() {
+      const service = getService();
+      if (service) service.setStyles(context, null);
+    }
+    async function update() {
+      var _a3;
+      const zoom = ~~context.map().zoom();
+      const showViewfields = zoom >= viewFieldZoomLevel;
+      const service = getService();
+      let sequences = service ? service.sequences(projection2, zoom) : [];
+      let images = service && zoom >= imageMinZoom2 ? service.images(projection2) : [];
+      images = await filterImages(images);
+      sequences = await filterSequences(sequences, service);
+      let traces = layer.selectAll(".sequences").selectAll(".sequence").data(sequences, function(d2) {
+        return d2.properties.id;
       });
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
+      traces.exit().remove();
+      traces.enter().append("path").attr("class", "sequence").merge(traces).attr("d", svgPath(projection2).geojson);
+      const groups = layer.selectAll(".markers").selectAll(".viewfield-group").data(images, function(d2) {
+        return d2.id;
+      });
+      groups.exit().remove();
+      const groupsEnter = groups.enter().append("g").attr("class", "viewfield-group").on("mouseenter", mouseover).on("mouseleave", mouseout).on("click", click);
+      groupsEnter.append("g").attr("class", "viewfield-scale");
+      const activeImageId = (_a3 = service.getActiveImage()) == null ? void 0 : _a3.id;
+      const markers = groups.merge(groupsEnter).sort(function(a2, b2) {
+        if (a2.id === activeImageId) return 1;
+        if (b2.id === activeImageId) return -1;
+        return a2.capture_time_parsed - b2.capture_time_parsed;
+      }).attr("transform", (d2) => transform2(d2, activeImageId)).select(".viewfield-scale");
+      markers.selectAll("circle").data([0]).enter().append("circle").attr("dx", "0").attr("dy", "0").attr("r", "6");
+      const viewfields = markers.selectAll(".viewfield").data(showViewfields ? [0] : []);
+      viewfields.exit().remove();
+      viewfields.enter().insert("path", "circle").attr("class", "viewfield").attr("transform", "scale(1.5,1.5),translate(-8, -13)").attr("d", viewfieldPath);
+      service.setStyles(context, null);
+      function viewfieldPath() {
+        if (this.parentNode.__data__.isPano) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
       }
     }
-    function play() {
-      dispatch10.call("done");
-      reveal(
-        ".ideditor",
-        helpHtml("intro.areas.play", { next: _t("intro.lines.title") }),
-        {
-          tooltipBox: ".intro-nav-wrap .chapter-line",
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            reveal(".ideditor");
+    function viewerChanged() {
+      const service = getService();
+      if (!service) return;
+      const frame2 = service.photoFrame();
+      if (!frame2) return;
+      _viewerYaw = frame2.getYaw();
+      if (context.map().isTransformed()) return;
+      layer.selectAll(".viewfield-group.currentView").attr("transform", (d2) => transform2(d2, d2.id));
+    }
+    function drawImages(selection2) {
+      const enabled = svgPanoramaxImages.enabled;
+      const service = getService();
+      layer = selection2.selectAll(".layer-panoramax").data(service ? [0] : []);
+      layer.exit().remove();
+      const layerEnter = layer.enter().append("g").attr("class", "layer-panoramax").style("display", enabled ? "block" : "none");
+      layerEnter.append("g").attr("class", "sequences");
+      layerEnter.append("g").attr("class", "markers");
+      layer = layerEnter.merge(layer);
+      if (enabled) {
+        let zoom = ~~context.map().zoom();
+        if (service) {
+          if (zoom >= imageMinZoom2) {
+            editOn();
+            update();
+            service.loadImages(projection2);
+          } else if (zoom >= lineMinZoom2) {
+            editOn();
+            update();
+            service.loadLines(projection2, zoom);
+          } else {
+            editOff();
           }
+        } else {
+          editOff();
         }
-      );
+      }
     }
-    chapter.enter = function() {
-      addArea();
+    drawImages.enabled = function(_2) {
+      if (!arguments.length) return svgPanoramaxImages.enabled;
+      svgPanoramaxImages.enabled = _2;
+      if (svgPanoramaxImages.enabled) {
+        showLayer();
+        context.photos().on("change.panoramax_images", update);
+      } else {
+        hideLayer();
+        context.photos().on("change.panoramax_images", null);
+      }
+      dispatch14.call("change");
+      return this;
     };
-    chapter.exit = function() {
-      timeouts.forEach(window.clearTimeout);
-      context.on("enter.intro exit.intro", null);
-      context.map().on("move.intro drawn.intro", null);
-      context.history().on("change.intro", null);
-      context.container().select(".inspector-wrap").on("wheel.intro", null);
-      context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
-      context.container().select(".more-fields .combobox-input").on("click.intro", null);
+    drawImages.supported = function() {
+      return !!getService();
     };
-    chapter.restart = function() {
-      chapter.exit();
-      chapter.enter();
+    drawImages.rendered = function(zoom) {
+      return zoom >= lineMinZoom2;
     };
-    return utilRebind(chapter, dispatch10, "on");
+    init2();
+    return drawImages;
   }
 
-  // modules/ui/intro/line.js
-  function uiIntroLine(context, reveal) {
-    var dispatch10 = dispatch_default("done");
-    var timeouts = [];
-    var _tulipRoadID = null;
-    var flowerRoadID = "w646";
-    var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
-    var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
-    var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
-    var roadCategory = _mainPresetIndex.item("category-road_minor");
-    var residentialPreset = _mainPresetIndex.item("highway/residential");
-    var woodRoadID = "w525";
-    var woodRoadEndID = "n2862";
-    var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
-    var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
-    var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
-    var washingtonStreetID = "w522";
-    var twelfthAvenueID = "w1";
-    var eleventhAvenueEndID = "n3550";
-    var twelfthAvenueEndID = "n5";
-    var _washingtonSegmentID = null;
-    var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
-    var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
-    var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
-    var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
-    var chapter = {
-      title: "intro.lines.title"
-    };
-    function timeout2(f2, t) {
-      timeouts.push(window.setTimeout(f2, t));
+  // modules/svg/osm.js
+  function svgOsm(projection2, context, dispatch14) {
+    var enabled = true;
+    function drawOsm(selection2) {
+      selection2.selectAll(".layer-osm").data(["covered", "areas", "lines", "points", "labels"]).enter().append("g").attr("class", function(d2) {
+        return "layer-osm " + d2;
+      });
+      selection2.selectAll(".layer-osm.points").selectAll(".points-group").data(["points", "midpoints", "vertices", "turns"]).enter().append("g").attr("class", function(d2) {
+        return "points-group " + d2;
+      });
     }
-    function eventCancel(d3_event) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
+    function showLayer() {
+      var layer = context.surface().selectAll(".data-layer.osm");
+      layer.interrupt();
+      layer.classed("disabled", false).style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", function() {
+        dispatch14.call("change");
+      });
     }
-    function addLine() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      var msec = transitionTime(tulipRoadStart, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
-      }
-      context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
-      timeout2(function() {
-        var tooltip = reveal(
-          "button.add-line",
-          helpHtml("intro.lines.add_line")
-        );
-        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-lines");
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-line")
-            return;
-          continueTo(startLine);
-        });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        nextStep();
+    function hideLayer() {
+      var layer = context.surface().selectAll(".data-layer.osm");
+      layer.interrupt();
+      layer.transition().duration(250).style("opacity", 0).on("end interrupt", function() {
+        layer.classed("disabled", true);
+        dispatch14.call("change");
+      });
+    }
+    drawOsm.enabled = function(val) {
+      if (!arguments.length) return enabled;
+      enabled = val;
+      if (enabled) {
+        showLayer();
+      } else {
+        hideLayer();
       }
+      dispatch14.call("change");
+      return this;
+    };
+    return drawOsm;
+  }
+
+  // modules/svg/notes.js
+  var _notesEnabled = false;
+  var _osmService;
+  function svgNotes(projection2, context, dispatch14) {
+    if (!dispatch14) {
+      dispatch14 = dispatch_default("change");
     }
-    function startLine() {
-      if (context.mode().id !== "add-line")
-        return chapter.restart();
-      _tulipRoadID = null;
-      var padding = 70 * Math.pow(2, context.map().zoom() - 18);
-      var box = pad(tulipRoadStart, padding, context);
-      box.height = box.height + 100;
-      var textId = context.lastPointerType() === "mouse" ? "start_line" : "start_line_tap";
-      var startLineString = helpHtml("intro.lines.missing_road") + "{br}" + helpHtml("intro.lines.line_draw_info") + helpHtml("intro.lines." + textId);
-      reveal(box, startLineString);
-      context.map().on("move.intro drawn.intro", function() {
-        padding = 70 * Math.pow(2, context.map().zoom() - 18);
-        box = pad(tulipRoadStart, padding, context);
-        box.height = box.height + 100;
-        reveal(box, startLineString, { duration: 0 });
-      });
-      context.on("enter.intro", function(mode) {
-        if (mode.id !== "draw-line")
-          return chapter.restart();
-        continueTo(drawLine);
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
-      }
+    var throttledRedraw = throttle_default(function() {
+      dispatch14.call("change");
+    }, 1e3);
+    var minZoom5 = 12;
+    var touchLayer = select_default2(null);
+    var drawLayer = select_default2(null);
+    var _notesVisible = false;
+    function markerPath(selection2, klass) {
+      selection2.attr("class", klass).attr("transform", "translate(-8, -22)").attr("d", "m17.5,0l-15,0c-1.37,0 -2.5,1.12 -2.5,2.5l0,11.25c0,1.37 1.12,2.5 2.5,2.5l3.75,0l0,3.28c0,0.38 0.43,0.6 0.75,0.37l4.87,-3.65l5.62,0c1.37,0 2.5,-1.12 2.5,-2.5l0,-11.25c0,-1.37 -1.12,-2.5 -2.5,-2.5z");
     }
-    function drawLine() {
-      if (context.mode().id !== "draw-line")
-        return chapter.restart();
-      _tulipRoadID = context.mode().selectedIDs()[0];
-      context.map().centerEase(tulipRoadMidpoint, 500);
-      timeout2(function() {
-        var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
-        var box = pad(tulipRoadMidpoint, padding, context);
-        box.height = box.height * 2;
-        reveal(
-          box,
-          helpHtml("intro.lines.intersect", { name: _t("intro.graph.name.flower-street") })
-        );
-        context.map().on("move.intro drawn.intro", function() {
-          padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
-          box = pad(tulipRoadMidpoint, padding, context);
-          box.height = box.height * 2;
-          reveal(
-            box,
-            helpHtml("intro.lines.intersect", { name: _t("intro.graph.name.flower-street") }),
-            { duration: 0 }
-          );
-        });
-      }, 550);
-      context.history().on("change.intro", function() {
-        if (isLineConnected()) {
-          continueTo(continueLine);
-        }
-      });
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "draw-line") {
-          return;
-        } else if (mode.id === "select") {
-          continueTo(retryIntersect);
-          return;
-        } else {
-          return chapter.restart();
-        }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
+    function getService() {
+      if (services.osm && !_osmService) {
+        _osmService = services.osm;
+        _osmService.on("loadedNotes", throttledRedraw);
+      } else if (!services.osm && _osmService) {
+        _osmService = null;
       }
+      return _osmService;
     }
-    function isLineConnected() {
-      var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
-      if (!entity)
-        return false;
-      var drawNodes = context.graph().childNodes(entity);
-      return drawNodes.some(function(node) {
-        return context.graph().parentWays(node).some(function(parent) {
-          return parent.id === flowerRoadID;
-        });
-      });
+    function editOn() {
+      if (!_notesVisible) {
+        _notesVisible = true;
+        drawLayer.style("display", "block");
+      }
     }
-    function retryIntersect() {
-      select_default2(window).on("pointerdown.intro mousedown.intro", eventCancel, true);
-      var box = pad(tulipRoadIntersection, 80, context);
-      reveal(
-        box,
-        helpHtml("intro.lines.retry_intersect", { name: _t("intro.graph.name.flower-street") })
-      );
-      timeout2(chapter.restart, 3e3);
+    function editOff() {
+      if (_notesVisible) {
+        _notesVisible = false;
+        drawLayer.style("display", "none");
+        drawLayer.selectAll(".note").remove();
+        touchLayer.selectAll(".note").remove();
+      }
     }
-    function continueLine() {
-      if (context.mode().id !== "draw-line")
-        return chapter.restart();
-      var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
-      if (!entity)
-        return chapter.restart();
-      context.map().centerEase(tulipRoadIntersection, 500);
-      var continueLineText = helpHtml("intro.lines.continue_line") + "{br}" + helpHtml("intro.lines.finish_line_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.lines.finish_road");
-      reveal(".surface", continueLineText);
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "draw-line") {
-          return;
-        } else if (mode.id === "select") {
-          return continueTo(chooseCategoryRoad);
-        } else {
-          return chapter.restart();
-        }
+    function layerOn() {
+      editOn();
+      drawLayer.style("opacity", 0).transition().duration(250).style("opacity", 1).on("end interrupt", function() {
+        dispatch14.call("change");
       });
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        nextStep();
-      }
     }
-    function chooseCategoryRoad() {
-      if (context.mode().id !== "select")
-        return chapter.restart();
-      context.on("exit.intro", function() {
-        return chapter.restart();
+    function layerOff() {
+      throttledRedraw.cancel();
+      drawLayer.interrupt();
+      touchLayer.selectAll(".note").remove();
+      drawLayer.transition().duration(250).style("opacity", 0).on("end interrupt", function() {
+        editOff();
+        dispatch14.call("change");
       });
-      var button = context.container().select(".preset-category-road_minor .preset-list-button");
-      if (button.empty())
-        return chapter.restart();
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      timeout2(function() {
-        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
-        reveal(
-          button.node(),
-          helpHtml("intro.lines.choose_category_road", { category: roadCategory.name() })
-        );
-        button.on("click.intro", function() {
-          continueTo(choosePresetResidential);
-        });
-      }, 400);
-      function continueTo(nextStep) {
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.container().select(".preset-list-button").on("click.intro", null);
-        context.on("exit.intro", null);
-        nextStep();
-      }
     }
-    function choosePresetResidential() {
-      if (context.mode().id !== "select")
-        return chapter.restart();
-      context.on("exit.intro", function() {
-        return chapter.restart();
+    function updateMarkers() {
+      if (!_notesVisible || !_notesEnabled) return;
+      var service = getService();
+      var selectedID = context.selectedNoteID();
+      var data = service ? service.notes(projection2) : [];
+      var getTransform = svgPointTransform(projection2);
+      var notes = drawLayer.selectAll(".note").data(data, function(d2) {
+        return d2.status + d2.id;
       });
-      var subgrid = context.container().select(".preset-category-road_minor .subgrid");
-      if (subgrid.empty())
-        return chapter.restart();
-      subgrid.selectAll(":not(.preset-highway-residential) .preset-list-button").on("click.intro", function() {
-        continueTo(retryPresetResidential);
+      notes.exit().remove();
+      var notesEnter = notes.enter().append("g").attr("class", function(d2) {
+        return "note note-" + d2.id + " " + d2.status;
+      }).classed("new", function(d2) {
+        return d2.id < 0;
       });
-      subgrid.selectAll(".preset-highway-residential .preset-list-button").on("click.intro", function() {
-        continueTo(nameRoad);
+      notesEnter.append("ellipse").attr("cx", 0.5).attr("cy", 1).attr("rx", 6.5).attr("ry", 3).attr("class", "stroke");
+      notesEnter.append("path").call(markerPath, "shadow");
+      notesEnter.append("use").attr("class", "note-fill").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").attr("xlink:href", "#iD-icon-note");
+      notesEnter.selectAll(".icon-annotation").data(function(d2) {
+        return [d2];
+      }).enter().append("use").attr("class", "icon-annotation").attr("width", "10px").attr("height", "10px").attr("x", "-3px").attr("y", "-19px").attr("xlink:href", function(d2) {
+        if (d2.id < 0) return "#iD-icon-plus";
+        if (d2.status === "open") return "#iD-icon-close";
+        return "#iD-icon-apply";
       });
-      timeout2(function() {
-        reveal(
-          subgrid.node(),
-          helpHtml("intro.lines.choose_preset_residential", { preset: residentialPreset.name() }),
-          { tooltipBox: ".preset-highway-residential .preset-list-button", duration: 300 }
-        );
-      }, 300);
-      function continueTo(nextStep) {
-        context.container().select(".preset-list-button").on("click.intro", null);
-        context.on("exit.intro", null);
-        nextStep();
-      }
-    }
-    function retryPresetResidential() {
-      if (context.mode().id !== "select")
-        return chapter.restart();
-      context.on("exit.intro", function() {
-        return chapter.restart();
+      notes.merge(notesEnter).sort(sortY).classed("selected", function(d2) {
+        var mode = context.mode();
+        var isMoving = mode && mode.id === "drag-note";
+        return !isMoving && d2.id === selectedID;
+      }).attr("transform", getTransform);
+      if (touchLayer.empty()) return;
+      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
+      var targets = touchLayer.selectAll(".note").data(data, function(d2) {
+        return d2.id;
       });
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      timeout2(function() {
-        var button = context.container().select(".entity-editor-pane .preset-list-button");
-        reveal(
-          button.node(),
-          helpHtml("intro.lines.retry_preset_residential", { preset: residentialPreset.name() })
-        );
-        button.on("click.intro", function() {
-          continueTo(chooseCategoryRoad);
-        });
-      }, 500);
-      function continueTo(nextStep) {
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.container().select(".preset-list-button").on("click.intro", null);
-        context.on("exit.intro", null);
-        nextStep();
+      targets.exit().remove();
+      targets.enter().append("rect").attr("width", "20px").attr("height", "20px").attr("x", "-8px").attr("y", "-22px").merge(targets).sort(sortY).attr("class", function(d2) {
+        var newClass = d2.id < 0 ? "new" : "";
+        return "note target note-" + d2.id + " " + fillClass + newClass;
+      }).attr("transform", getTransform);
+      function sortY(a2, b2) {
+        if (a2.id === selectedID) return 1;
+        if (b2.id === selectedID) return -1;
+        return b2.loc[1] - a2.loc[1];
       }
     }
-    function nameRoad() {
-      context.on("exit.intro", function() {
-        continueTo(didNameRoad);
-      });
-      timeout2(function() {
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.lines.name_road", { button: { html: icon("#iD-icon-close", "inline") } }),
-          { tooltipClass: "intro-lines-name_road" }
-        );
-      }, 500);
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
+    function drawNotes(selection2) {
+      var service = getService();
+      var surface = context.surface();
+      if (surface && !surface.empty()) {
+        touchLayer = surface.selectAll(".data-layer.touch .layer-touch.markers");
       }
-    }
-    function didNameRoad() {
-      context.history().checkpoint("doneAddLine");
-      timeout2(function() {
-        reveal(".surface", helpHtml("intro.lines.did_name_road"), {
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            continueTo(updateLine);
-          }
-        });
-      }, 500);
-      function continueTo(nextStep) {
-        nextStep();
+      drawLayer = selection2.selectAll(".layer-notes").data(service ? [0] : []);
+      drawLayer.exit().remove();
+      drawLayer = drawLayer.enter().append("g").attr("class", "layer-notes").style("display", _notesEnabled ? "block" : "none").merge(drawLayer);
+      if (_notesEnabled) {
+        if (service && ~~context.map().zoom() >= minZoom5) {
+          editOn();
+          service.loadNotes(projection2);
+          updateMarkers();
+        } else {
+          editOff();
+        }
       }
     }
-    function updateLine() {
-      context.history().reset("doneAddLine");
-      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-        return chapter.restart();
-      }
-      var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
-      }
-      context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
-      timeout2(function() {
-        var padding = 250 * Math.pow(2, context.map().zoom() - 19);
-        var box = pad(woodRoadDragMidpoint, padding, context);
-        var advance = function() {
-          continueTo(addNode);
-        };
-        reveal(
-          box,
-          helpHtml("intro.lines.update_line"),
-          { buttonText: _t.html("intro.ok"), buttonCallback: advance }
-        );
-        context.map().on("move.intro drawn.intro", function() {
-          var padding2 = 250 * Math.pow(2, context.map().zoom() - 19);
-          var box2 = pad(woodRoadDragMidpoint, padding2, context);
-          reveal(
-            box2,
-            helpHtml("intro.lines.update_line"),
-            { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
-          );
-        });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
+    drawNotes.enabled = function(val) {
+      if (!arguments.length) return _notesEnabled;
+      _notesEnabled = val;
+      if (_notesEnabled) {
+        layerOn();
+      } else {
+        layerOff();
+        if (context.selectedNoteID()) {
+          context.enter(modeBrowse(context));
+        }
       }
+      dispatch14.call("change");
+      return this;
+    };
+    return drawNotes;
+  }
+
+  // modules/svg/touch.js
+  function svgTouch() {
+    function drawTouch(selection2) {
+      selection2.selectAll(".layer-touch").data(["areas", "lines", "points", "turns", "markers"]).enter().append("g").attr("class", function(d2) {
+        return "layer-touch " + d2;
+      });
     }
-    function addNode() {
-      context.history().reset("doneAddLine");
-      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-        return chapter.restart();
-      }
-      var padding = 40 * Math.pow(2, context.map().zoom() - 19);
-      var box = pad(woodRoadAddNode, padding, context);
-      var addNodeString = helpHtml("intro.lines.add_node" + (context.lastPointerType() === "mouse" ? "" : "_touch"));
-      reveal(box, addNodeString);
-      context.map().on("move.intro drawn.intro", function() {
-        var padding2 = 40 * Math.pow(2, context.map().zoom() - 19);
-        var box2 = pad(woodRoadAddNode, padding2, context);
-        reveal(box2, addNodeString, { duration: 0 });
+    return drawTouch;
+  }
+
+  // modules/util/dimensions.js
+  function refresh(selection2, node) {
+    var cr = node.getBoundingClientRect();
+    var prop = [cr.width, cr.height];
+    selection2.property("__dimensions__", prop);
+    return prop;
+  }
+  function utilGetDimensions(selection2, force) {
+    if (!selection2 || selection2.empty()) {
+      return [0, 0];
+    }
+    var node = selection2.node(), cached = selection2.property("__dimensions__");
+    return !cached || force ? refresh(selection2, node) : cached;
+  }
+  function utilSetDimensions(selection2, dimensions) {
+    if (!selection2 || selection2.empty()) {
+      return selection2;
+    }
+    var node = selection2.node();
+    if (dimensions === null) {
+      refresh(selection2, node);
+      return selection2;
+    }
+    return selection2.property("__dimensions__", [dimensions[0], dimensions[1]]).attr("width", dimensions[0]).attr("height", dimensions[1]);
+  }
+
+  // modules/svg/layers.js
+  function svgLayers(projection2, context) {
+    var dispatch14 = dispatch_default("change");
+    var svg2 = select_default2(null);
+    var _layers = [
+      { id: "osm", layer: svgOsm(projection2, context, dispatch14) },
+      { id: "notes", layer: svgNotes(projection2, context, dispatch14) },
+      { id: "data", layer: svgData(projection2, context, dispatch14) },
+      { id: "keepRight", layer: svgKeepRight(projection2, context, dispatch14) },
+      { id: "osmose", layer: svgOsmose(projection2, context, dispatch14) },
+      { id: "streetside", layer: svgStreetside(projection2, context, dispatch14) },
+      { id: "mapillary", layer: svgMapillaryImages(projection2, context, dispatch14) },
+      { id: "mapillary-position", layer: svgMapillaryPosition(projection2, context, dispatch14) },
+      { id: "mapillary-map-features", layer: svgMapillaryMapFeatures(projection2, context, dispatch14) },
+      { id: "mapillary-signs", layer: svgMapillarySigns(projection2, context, dispatch14) },
+      { id: "kartaview", layer: svgKartaviewImages(projection2, context, dispatch14) },
+      { id: "mapilio", layer: svgMapilioImages(projection2, context, dispatch14) },
+      { id: "vegbilder", layer: svgVegbilder(projection2, context, dispatch14) },
+      { id: "panoramax", layer: svgPanoramaxImages(projection2, context, dispatch14) },
+      { id: "local-photos", layer: svgLocalPhotos(projection2, context, dispatch14) },
+      { id: "debug", layer: svgDebug(projection2, context, dispatch14) },
+      { id: "geolocate", layer: svgGeolocate(projection2, context, dispatch14) },
+      { id: "touch", layer: svgTouch(projection2, context, dispatch14) }
+    ];
+    function drawLayers(selection2) {
+      svg2 = selection2.selectAll(".surface").data([0]);
+      svg2 = svg2.enter().append("svg").attr("class", "surface").merge(svg2);
+      var defs = svg2.selectAll(".surface-defs").data([0]);
+      defs.enter().append("defs").attr("class", "surface-defs");
+      var groups = svg2.selectAll(".data-layer").data(_layers);
+      groups.exit().remove();
+      groups.enter().append("g").attr("class", function(d2) {
+        return "data-layer " + d2.id;
+      }).merge(groups).each(function(d2) {
+        select_default2(this).call(d2.layer);
       });
-      context.history().on("change.intro", function(changed) {
-        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-          return continueTo(updateLine);
-        }
-        if (changed.created().length === 1) {
-          timeout2(function() {
-            continueTo(startDragEndpoint);
-          }, 500);
-        }
+    }
+    drawLayers.all = function() {
+      return _layers;
+    };
+    drawLayers.layer = function(id2) {
+      var obj = _layers.find(function(o2) {
+        return o2.id === id2;
       });
-      context.on("enter.intro", function(mode) {
-        if (mode.id !== "select") {
-          continueTo(updateLine);
-        }
+      return obj && obj.layer;
+    };
+    drawLayers.only = function(what) {
+      var arr = [].concat(what);
+      var all = _layers.map(function(layer) {
+        return layer.id;
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
-      }
-    }
-    function startDragEndpoint() {
-      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-        return continueTo(updateLine);
-      }
-      var padding = 100 * Math.pow(2, context.map().zoom() - 19);
-      var box = pad(woodRoadDragEndpoint, padding, context);
-      var startDragString = helpHtml("intro.lines.start_drag_endpoint" + (context.lastPointerType() === "mouse" ? "" : "_touch")) + helpHtml("intro.lines.drag_to_intersection");
-      reveal(box, startDragString);
-      context.map().on("move.intro drawn.intro", function() {
-        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-          return continueTo(updateLine);
+      return drawLayers.remove(utilArrayDifference(all, arr));
+    };
+    drawLayers.remove = function(what) {
+      var arr = [].concat(what);
+      arr.forEach(function(id2) {
+        _layers = _layers.filter(function(o2) {
+          return o2.id !== id2;
+        });
+      });
+      dispatch14.call("change");
+      return this;
+    };
+    drawLayers.add = function(what) {
+      var arr = [].concat(what);
+      arr.forEach(function(obj) {
+        if ("id" in obj && "layer" in obj) {
+          _layers.push(obj);
         }
-        var padding2 = 100 * Math.pow(2, context.map().zoom() - 19);
-        var box2 = pad(woodRoadDragEndpoint, padding2, context);
-        reveal(box2, startDragString, { duration: 0 });
-        var entity = context.entity(woodRoadEndID);
-        if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
-          continueTo(finishDragEndpoint);
+      });
+      dispatch14.call("change");
+      return this;
+    };
+    drawLayers.dimensions = function(val) {
+      if (!arguments.length) return utilGetDimensions(svg2);
+      utilSetDimensions(svg2, val);
+      return this;
+    };
+    return utilRebind(drawLayers, dispatch14, "on");
+  }
+
+  // modules/svg/lines.js
+  var import_fast_deep_equal6 = __toESM(require_fast_deep_equal());
+  function svgLines(projection2, context) {
+    var detected = utilDetect();
+    var highway_stack = {
+      motorway: 0,
+      motorway_link: 1,
+      trunk: 2,
+      trunk_link: 3,
+      primary: 4,
+      primary_link: 5,
+      secondary: 6,
+      tertiary: 7,
+      unclassified: 8,
+      residential: 9,
+      service: 10,
+      busway: 11,
+      footway: 12
+    };
+    function drawTargets(selection2, graph, entities, filter2) {
+      var targetClass = context.getDebug("target") ? "pink " : "nocolor ";
+      var nopeClass = context.getDebug("target") ? "red " : "nocolor ";
+      var getPath = svgPath(projection2).geojson;
+      var activeID = context.activeID();
+      var base = context.history().base();
+      var data = { targets: [], nopes: [] };
+      entities.forEach(function(way) {
+        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(d2) {
+        return filter2(d2.properties.entity);
+      }).data(targetData, function key(d2) {
+        return d2.id;
+      });
+      targets.exit().remove();
+      var segmentWasEdited = function(d2) {
+        var wayID = d2.properties.entity.id;
+        if (!base.entities[wayID] || !(0, import_fast_deep_equal6.default)(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
+          return false;
         }
+        return d2.properties.nodes.some(function(n3) {
+          return !base.entities[n3.id] || !(0, import_fast_deep_equal6.default)(graph.entities[n3.id].loc, base.entities[n3.id].loc);
+        });
+      };
+      targets.enter().append("path").merge(targets).attr("d", getPath).attr("class", function(d2) {
+        return "way line target target-allowed " + targetClass + d2.id;
+      }).classed("segment-edited", segmentWasEdited);
+      var nopeData = data.nopes.filter(getPath);
+      var nopes = selection2.selectAll(".line.target-nope").filter(function(d2) {
+        return filter2(d2.properties.entity);
+      }).data(nopeData, function key(d2) {
+        return d2.id;
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
-      }
+      nopes.exit().remove();
+      nopes.enter().append("path").merge(nopes).attr("d", getPath).attr("class", function(d2) {
+        return "way line target target-nope " + nopeClass + d2.id;
+      }).classed("segment-edited", segmentWasEdited);
     }
-    function finishDragEndpoint() {
-      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-        return continueTo(updateLine);
-      }
-      var padding = 100 * Math.pow(2, context.map().zoom() - 19);
-      var box = pad(woodRoadDragEndpoint, padding, context);
-      var finishDragString = helpHtml("intro.lines.spot_looks_good") + helpHtml("intro.lines.finish_drag_endpoint" + (context.lastPointerType() === "mouse" ? "" : "_touch"));
-      reveal(box, finishDragString);
-      context.map().on("move.intro drawn.intro", function() {
-        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-          return continueTo(updateLine);
+    function drawLines(selection2, graph, entities, filter2) {
+      var base = context.history().base();
+      function waystack(a2, b2) {
+        var selected = context.selectedIDs();
+        var scoreA = selected.indexOf(a2.id) !== -1 ? 20 : 0;
+        var scoreB = selected.indexOf(b2.id) !== -1 ? 20 : 0;
+        if (a2.tags.highway) {
+          scoreA -= highway_stack[a2.tags.highway];
         }
-        var padding2 = 100 * Math.pow(2, context.map().zoom() - 19);
-        var box2 = pad(woodRoadDragEndpoint, padding2, context);
-        reveal(box2, finishDragString, { duration: 0 });
-        var entity = context.entity(woodRoadEndID);
-        if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
-          continueTo(startDragEndpoint);
+        if (b2.tags.highway) {
+          scoreB -= highway_stack[b2.tags.highway];
         }
-      });
-      context.on("enter.intro", function() {
-        continueTo(startDragMidpoint);
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
-      }
-    }
-    function startDragMidpoint() {
-      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-        return continueTo(updateLine);
-      }
-      if (context.selectedIDs().indexOf(woodRoadID) === -1) {
-        context.enter(modeSelect(context, [woodRoadID]));
+        return scoreA - scoreB;
       }
-      var padding = 80 * Math.pow(2, context.map().zoom() - 19);
-      var box = pad(woodRoadDragMidpoint, padding, context);
-      reveal(box, helpHtml("intro.lines.start_drag_midpoint"));
-      context.map().on("move.intro drawn.intro", function() {
-        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-          return continueTo(updateLine);
-        }
-        var padding2 = 80 * Math.pow(2, context.map().zoom() - 19);
-        var box2 = pad(woodRoadDragMidpoint, padding2, context);
-        reveal(box2, helpHtml("intro.lines.start_drag_midpoint"), { duration: 0 });
-      });
-      context.history().on("change.intro", function(changed) {
-        if (changed.created().length === 1) {
-          continueTo(continueDragMidpoint);
-        }
-      });
-      context.on("enter.intro", function(mode) {
-        if (mode.id !== "select") {
-          context.enter(modeSelect(context, [woodRoadID]));
-        }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
-      }
-    }
-    function continueDragMidpoint() {
-      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-        return continueTo(updateLine);
-      }
-      var padding = 100 * Math.pow(2, context.map().zoom() - 19);
-      var box = pad(woodRoadDragEndpoint, padding, context);
-      box.height += 400;
-      var advance = function() {
-        context.history().checkpoint("doneUpdateLine");
-        continueTo(deleteLines);
-      };
-      reveal(
-        box,
-        helpHtml("intro.lines.continue_drag_midpoint"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: advance }
-      );
-      context.map().on("move.intro drawn.intro", function() {
-        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
-          return continueTo(updateLine);
-        }
-        var padding2 = 100 * Math.pow(2, context.map().zoom() - 19);
-        var box2 = pad(woodRoadDragEndpoint, padding2, context);
-        box2.height += 400;
-        reveal(
-          box2,
-          helpHtml("intro.lines.continue_drag_midpoint"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
-      }
-    }
-    function deleteLines() {
-      context.history().reset("doneUpdateLine");
-      context.enter(modeBrowse(context));
-      if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-        return chapter.restart();
-      }
-      var msec = transitionTime(deleteLinesLoc, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
+      function drawLineGroup(selection3, klass, isSelected) {
+        var mode = context.mode();
+        var isDrawing = mode && /^draw/.test(mode.id);
+        var selectedClass = !isDrawing && isSelected ? "selected " : "";
+        var lines = selection3.selectAll("path").filter(filter2).data(getPathData(isSelected), osmEntity.key);
+        lines.exit().remove();
+        lines.enter().append("path").attr("class", function(d2) {
+          var prefix = "way line";
+          if (!d2.hasInterestingTags()) {
+            var parentRelations = graph.parentRelations(d2);
+            var parentMultipolygons = parentRelations.filter(function(relation) {
+              return relation.isMultipolygon();
+            });
+            if (parentMultipolygons.length > 0 && // and only multipolygon relations
+            parentRelations.length === parentMultipolygons.length) {
+              prefix = "relation area";
+            }
+          }
+          var oldMPClass = oldMultiPolygonOuters[d2.id] ? "old-multipolygon " : "";
+          return prefix + " " + klass + " " + selectedClass + oldMPClass + d2.id;
+        }).classed("added", function(d2) {
+          return !base.entities[d2.id];
+        }).classed("geometry-edited", function(d2) {
+          return graph.entities[d2.id] && base.entities[d2.id] && !(0, import_fast_deep_equal6.default)(graph.entities[d2.id].nodes, base.entities[d2.id].nodes);
+        }).classed("retagged", function(d2) {
+          return graph.entities[d2.id] && base.entities[d2.id] && !(0, import_fast_deep_equal6.default)(graph.entities[d2.id].tags, base.entities[d2.id].tags);
+        }).call(svgTagClasses()).merge(lines).sort(waystack).attr("d", getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
+        return selection3;
       }
-      context.map().centerZoomEase(deleteLinesLoc, 18, msec);
-      timeout2(function() {
-        var padding = 200 * Math.pow(2, context.map().zoom() - 18);
-        var box = pad(deleteLinesLoc, padding, context);
-        box.top -= 200;
-        box.height += 400;
-        var advance = function() {
-          continueTo(rightClickIntersection);
+      function getPathData(isSelected) {
+        return function() {
+          var layer = this.parentNode.__data__;
+          var data = pathdata[layer] || [];
+          return data.filter(function(d2) {
+            if (isSelected) {
+              return context.selectedIDs().indexOf(d2.id) !== -1;
+            } else {
+              return context.selectedIDs().indexOf(d2.id) === -1;
+            }
+          });
         };
-        reveal(
-          box,
-          helpHtml("intro.lines.delete_lines", { street: _t("intro.graph.name.12th-avenue") }),
-          { buttonText: _t.html("intro.ok"), buttonCallback: advance }
+      }
+      function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
+        var markergroup = layergroup.selectAll("g." + groupclass).data([pathclass]);
+        markergroup = markergroup.enter().append("g").attr("class", groupclass).merge(markergroup);
+        var markers = markergroup.selectAll("path").filter(filter2).data(
+          function data() {
+            return groupdata[this.parentNode.__data__] || [];
+          },
+          function key(d2) {
+            return [d2.id, d2.index];
+          }
         );
-        context.map().on("move.intro drawn.intro", function() {
-          var padding2 = 200 * Math.pow(2, context.map().zoom() - 18);
-          var box2 = pad(deleteLinesLoc, padding2, context);
-          box2.top -= 200;
-          box2.height += 400;
-          reveal(
-            box2,
-            helpHtml("intro.lines.delete_lines", { street: _t("intro.graph.name.12th-avenue") }),
-            { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
-          );
-        });
-        context.history().on("change.intro", function() {
-          timeout2(function() {
-            continueTo(deleteLines);
-          }, 500);
+        markers.exit().remove();
+        markers = markers.enter().append("path").attr("class", pathclass).merge(markers).attr("marker-mid", marker).attr("d", function(d2) {
+          return d2.d;
         });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+        if (detected.ie) {
+          markers.each(function() {
+            this.parentNode.insertBefore(this, this);
+          });
+        }
       }
-    }
-    function rightClickIntersection() {
-      context.history().reset("doneUpdateLine");
-      context.enter(modeBrowse(context));
-      context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
-      var rightClickString = helpHtml("intro.lines.split_street", {
-        street1: _t("intro.graph.name.11th-avenue"),
-        street2: _t("intro.graph.name.washington-street")
-      }) + helpHtml("intro.lines." + (context.lastPointerType() === "mouse" ? "rightclick_intersection" : "edit_menu_intersection_touch"));
-      timeout2(function() {
-        var padding = 60 * Math.pow(2, context.map().zoom() - 18);
-        var box = pad(eleventhAvenueEnd, padding, context);
-        reveal(box, rightClickString);
-        context.map().on("move.intro drawn.intro", function() {
-          var padding2 = 60 * Math.pow(2, context.map().zoom() - 18);
-          var box2 = pad(eleventhAvenueEnd, padding2, context);
-          reveal(
-            box2,
-            rightClickString,
-            { duration: 0 }
-          );
-        });
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "select")
-            return;
-          var ids = context.selectedIDs();
-          if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID)
-            return;
-          timeout2(function() {
-            var node = selectMenuItem(context, "split").node();
-            if (!node)
-              return;
-            continueTo(splitIntersection);
-          }, 50);
+      var getPath = svgPath(projection2, graph);
+      var ways = [];
+      var onewaydata = {};
+      var sideddata = {};
+      var oldMultiPolygonOuters = {};
+      for (var i3 = 0; i3 < entities.length; i3++) {
+        var entity = entities[i3];
+        if (entity.geometry(graph) === "line" || entity.geometry(graph) === "area" && entity.sidednessIdentifier && entity.sidednessIdentifier() === "coastline") {
+          ways.push(entity);
+        }
+      }
+      ways = ways.filter(getPath);
+      var pathdata = utilArrayGroupBy(ways, function(way) {
+        return way.layer();
+      });
+      Object.keys(pathdata).forEach(function(k2) {
+        var v2 = pathdata[k2];
+        var onewayArr = v2.filter(function(d2) {
+          return d2.isOneWay();
         });
-        context.history().on("change.intro", function() {
-          timeout2(function() {
-            continueTo(deleteLines);
-          }, 300);
+        var onewaySegments = svgMarkerSegments(
+          projection2,
+          graph,
+          35,
+          function shouldReverse(entity2) {
+            return entity2.tags.oneway === "-1" || entity2.tags.conveying === "backward";
+          },
+          function bothDirections(entity2) {
+            return entity2.tags.oneway === "alternating" || entity2.tags.oneway === "reversible" || entity2.tags.conveying === "reversible";
+          }
+        );
+        onewaydata[k2] = utilArrayFlatten(onewayArr.map(onewaySegments));
+        var sidedArr = v2.filter(function(d2) {
+          return d2.isSided();
         });
-      }, 600);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
-    }
-    function splitIntersection() {
-      if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-        return continueTo(deleteLines);
-      }
-      var node = selectMenuItem(context, "split").node();
-      if (!node) {
-        return continueTo(rightClickIntersection);
-      }
-      var wasChanged = false;
-      _washingtonSegmentID = null;
-      reveal(
-        ".edit-menu",
-        helpHtml(
-          "intro.lines.split_intersection",
-          { street: _t("intro.graph.name.washington-street") }
-        ),
-        { padding: 50 }
-      );
-      context.map().on("move.intro drawn.intro", function() {
-        var node2 = selectMenuItem(context, "split").node();
-        if (!wasChanged && !node2) {
-          return continueTo(rightClickIntersection);
-        }
-        reveal(
-          ".edit-menu",
-          helpHtml(
-            "intro.lines.split_intersection",
-            { street: _t("intro.graph.name.washington-street") }
-          ),
-          { duration: 0, padding: 50 }
+        var sidedSegments = svgMarkerSegments(
+          projection2,
+          graph,
+          30,
+          function shouldReverse() {
+            return false;
+          },
+          function bothDirections() {
+            return false;
+          }
         );
+        sideddata[k2] = utilArrayFlatten(sidedArr.map(sidedSegments));
       });
-      context.history().on("change.intro", function(changed) {
-        wasChanged = true;
-        timeout2(function() {
-          if (context.history().undoAnnotation() === _t("operations.split.annotation.line", { n: 1 })) {
-            _washingtonSegmentID = changed.created()[0].id;
-            continueTo(didSplit);
-          } else {
-            _washingtonSegmentID = null;
-            continueTo(retrySplit);
+      var covered = selection2.selectAll(".layer-osm.covered");
+      var uncovered = selection2.selectAll(".layer-osm.lines");
+      var touchLayer = selection2.selectAll(".layer-touch.lines");
+      [covered, uncovered].forEach(function(selection3) {
+        var range3 = selection3 === covered ? range(-10, 0) : range(0, 11);
+        var layergroup = selection3.selectAll("g.layergroup").data(range3);
+        layergroup = layergroup.enter().append("g").attr("class", function(d2) {
+          return "layergroup layer" + String(d2);
+        }).merge(layergroup);
+        layergroup.selectAll("g.linegroup").data(["shadow", "casing", "stroke", "shadow-highlighted", "casing-highlighted", "stroke-highlighted"]).enter().append("g").attr("class", function(d2) {
+          return "linegroup line-" + d2;
+        });
+        layergroup.selectAll("g.line-shadow").call(drawLineGroup, "shadow", false);
+        layergroup.selectAll("g.line-casing").call(drawLineGroup, "casing", false);
+        layergroup.selectAll("g.line-stroke").call(drawLineGroup, "stroke", false);
+        layergroup.selectAll("g.line-shadow-highlighted").call(drawLineGroup, "shadow", true);
+        layergroup.selectAll("g.line-casing-highlighted").call(drawLineGroup, "casing", true);
+        layergroup.selectAll("g.line-stroke-highlighted").call(drawLineGroup, "stroke", true);
+        addMarkers(layergroup, "oneway", "onewaygroup", onewaydata, "url(#ideditor-oneway-marker)");
+        addMarkers(
+          layergroup,
+          "sided",
+          "sidedgroup",
+          sideddata,
+          function marker(d2) {
+            var category = graph.entity(d2.id).sidednessIdentifier();
+            return "url(#ideditor-sided-marker-" + category + ")";
           }
-        }, 300);
+        );
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
+      touchLayer.call(drawTargets, graph, ways, filter2);
     }
-    function retrySplit() {
-      context.enter(modeBrowse(context));
-      context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
-      var advance = function() {
-        continueTo(rightClickIntersection);
-      };
-      var padding = 60 * Math.pow(2, context.map().zoom() - 18);
-      var box = pad(eleventhAvenueEnd, padding, context);
-      reveal(
-        box,
-        helpHtml("intro.lines.retry_split"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: advance }
-      );
-      context.map().on("move.intro drawn.intro", function() {
-        var padding2 = 60 * Math.pow(2, context.map().zoom() - 18);
-        var box2 = pad(eleventhAvenueEnd, padding2, context);
-        reveal(
-          box2,
-          helpHtml("intro.lines.retry_split"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
-        );
+    return drawLines;
+  }
+
+  // modules/svg/midpoints.js
+  function svgMidpoints(projection2, context) {
+    var targetRadius = 8;
+    function drawTargets(selection2, graph, entities, filter2) {
+      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
+      var getTransform = svgPointTransform(projection2).geojson;
+      var data = entities.map(function(midpoint) {
+        return {
+          type: "Feature",
+          id: midpoint.id,
+          properties: {
+            target: true,
+            entity: midpoint
+          },
+          geometry: {
+            type: "Point",
+            coordinates: midpoint.loc
+          }
+        };
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
-      }
+      var targets = selection2.selectAll(".midpoint.target").filter(function(d2) {
+        return filter2(d2.properties.entity);
+      }).data(data, function key(d2) {
+        return d2.id;
+      });
+      targets.exit().remove();
+      targets.enter().append("circle").attr("r", targetRadius).merge(targets).attr("class", function(d2) {
+        return "node midpoint target " + fillClass + d2.id;
+      }).attr("transform", getTransform);
     }
-    function didSplit() {
-      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-        return continueTo(rightClickIntersection);
+    function drawMidpoints(selection2, graph, entities, filter2, extent) {
+      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.midpoints");
+      var touchLayer = selection2.selectAll(".layer-touch.points");
+      var mode = context.mode();
+      if (mode && mode.id !== "select" || !context.map().withinEditableZoom()) {
+        drawLayer.selectAll(".midpoint").remove();
+        touchLayer.selectAll(".midpoint.target").remove();
+        return;
       }
-      var ids = context.selectedIDs();
-      var string = "intro.lines.did_split_" + (ids.length > 1 ? "multi" : "single");
-      var street = _t("intro.graph.name.washington-street");
-      var padding = 200 * Math.pow(2, context.map().zoom() - 18);
-      var box = pad(twelfthAvenue, padding, context);
-      box.width = box.width / 2;
-      reveal(
-        box,
-        helpHtml(string, { street1: street, street2: street }),
-        { duration: 500 }
-      );
-      timeout2(function() {
-        context.map().centerZoomEase(twelfthAvenue, 18, 500);
-        context.map().on("move.intro drawn.intro", function() {
-          var padding2 = 200 * Math.pow(2, context.map().zoom() - 18);
-          var box2 = pad(twelfthAvenue, padding2, context);
-          box2.width = box2.width / 2;
-          reveal(
-            box2,
-            helpHtml(string, { street1: street, street2: street }),
-            { duration: 0 }
-          );
-        });
-      }, 600);
-      context.on("enter.intro", function() {
-        var ids2 = context.selectedIDs();
-        if (ids2.length === 1 && ids2[0] === _washingtonSegmentID) {
-          continueTo(multiSelect);
+      var poly = extent.polygon();
+      var midpoints = {};
+      for (var i3 = 0; i3 < entities.length; i3++) {
+        var entity = entities[i3];
+        if (entity.type !== "way") continue;
+        if (!filter2(entity)) continue;
+        if (context.selectedIDs().indexOf(entity.id) < 0) continue;
+        var nodes = graph.childNodes(entity);
+        for (var j2 = 0; j2 < nodes.length - 1; j2++) {
+          var a2 = nodes[j2];
+          var b2 = nodes[j2 + 1];
+          var id2 = [a2.id, b2.id].sort().join("-");
+          if (midpoints[id2]) {
+            midpoints[id2].parents.push(entity);
+          } else if (geoVecLength(projection2(a2.loc), projection2(b2.loc)) > 40) {
+            var point = geoVecInterp(a2.loc, b2.loc, 0.5);
+            var loc = null;
+            if (extent.intersects(point)) {
+              loc = point;
+            } else {
+              for (var k2 = 0; k2 < 4; k2++) {
+                point = geoLineIntersection([a2.loc, b2.loc], [poly[k2], poly[k2 + 1]]);
+                if (point && geoVecLength(projection2(a2.loc), projection2(point)) > 20 && geoVecLength(projection2(b2.loc), projection2(point)) > 20) {
+                  loc = point;
+                  break;
+                }
+              }
+            }
+            if (loc) {
+              midpoints[id2] = {
+                type: "midpoint",
+                id: id2,
+                loc,
+                edge: [a2.id, b2.id],
+                parents: [entity]
+              };
+            }
+          }
+        }
+      }
+      function midpointFilter(d2) {
+        if (midpoints[d2.id]) return true;
+        for (var i4 = 0; i4 < d2.parents.length; i4++) {
+          if (filter2(d2.parents[i4])) {
+            return true;
+          }
         }
+        return false;
+      }
+      var groups = drawLayer.selectAll(".midpoint").filter(midpointFilter).data(Object.values(midpoints), function(d2) {
+        return d2.id;
       });
-      context.history().on("change.intro", function() {
-        if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-          return continueTo(rightClickIntersection);
+      groups.exit().remove();
+      var enter = groups.enter().insert("g", ":first-child").attr("class", "midpoint");
+      enter.append("polygon").attr("points", "-6,8 10,0 -6,-8").attr("class", "shadow");
+      enter.append("polygon").attr("points", "-3,4 5,0 -3,-4").attr("class", "fill");
+      groups = groups.merge(enter).attr("transform", function(d2) {
+        var translate = svgPointTransform(projection2);
+        var a3 = graph.entity(d2.edge[0]);
+        var b3 = graph.entity(d2.edge[1]);
+        var angle2 = geoAngle(a3, b3, projection2) * (180 / Math.PI);
+        return translate(d2) + " rotate(" + angle2 + ")";
+      }).call(svgTagClasses().tags(
+        function(d2) {
+          return d2.parents[0].tags;
         }
+      ));
+      groups.select("polygon.shadow");
+      groups.select("polygon.fill");
+      touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
+    }
+    return drawMidpoints;
+  }
+
+  // modules/svg/points.js
+  var import_fast_deep_equal7 = __toESM(require_fast_deep_equal());
+  function svgPoints(projection2, context) {
+    function markerPath(selection2, klass) {
+      selection2.attr("class", klass).attr("transform", "translate(-8, -23)").attr("d", "M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z");
+    }
+    function sortY(a2, b2) {
+      return b2.loc[1] - a2.loc[1];
+    }
+    function fastEntityKey(d2) {
+      var mode = context.mode();
+      var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
+      return isMoving ? d2.id : osmEntity.key(d2);
+    }
+    function drawTargets(selection2, graph, entities, filter2) {
+      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
+      var getTransform = svgPointTransform(projection2).geojson;
+      var activeID = context.activeID();
+      var data = [];
+      entities.forEach(function(node) {
+        if (activeID === node.id) return;
+        data.push({
+          type: "Feature",
+          id: node.id,
+          properties: {
+            target: true,
+            entity: node
+          },
+          geometry: node.asGeoJSON()
+        });
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
+      var targets = selection2.selectAll(".point.target").filter(function(d2) {
+        return filter2(d2.properties.entity);
+      }).data(data, function key(d2) {
+        return d2.id;
+      });
+      targets.exit().remove();
+      targets.enter().append("rect").attr("x", -10).attr("y", -26).attr("width", 20).attr("height", 30).merge(targets).attr("class", function(d2) {
+        return "node point target " + fillClass + d2.id;
+      }).attr("transform", getTransform);
     }
-    function multiSelect() {
-      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-        return continueTo(rightClickIntersection);
+    function drawPoints(selection2, graph, entities, filter2) {
+      var wireframe = context.surface().classed("fill-wireframe");
+      var zoom = geoScaleToZoom(projection2.scale());
+      var base = context.history().base();
+      function renderAsPoint(entity) {
+        return entity.geometry(graph) === "point" && !(zoom >= 18 && entity.directions(graph, projection2).length);
       }
-      var ids = context.selectedIDs();
-      var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
-      var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
-      if (hasWashington && hasTwelfth) {
-        return continueTo(multiRightClick);
-      } else if (!hasWashington && !hasTwelfth) {
-        return continueTo(didSplit);
+      var points = wireframe ? [] : entities.filter(renderAsPoint);
+      points.sort(sortY);
+      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.points");
+      var touchLayer = selection2.selectAll(".layer-touch.points");
+      var groups = drawLayer.selectAll("g.point").filter(filter2).data(points, fastEntityKey);
+      groups.exit().remove();
+      var enter = groups.enter().append("g").attr("class", function(d2) {
+        return "node point " + d2.id;
+      }).order();
+      enter.append("path").call(markerPath, "shadow");
+      enter.append("ellipse").attr("cx", 0.5).attr("cy", 1).attr("rx", 6.5).attr("ry", 3).attr("class", "stroke");
+      enter.append("path").call(markerPath, "stroke");
+      enter.append("use").attr("transform", "translate(-5.5, -20)").attr("class", "icon").attr("width", "12px").attr("height", "12px");
+      groups = groups.merge(enter).attr("transform", svgPointTransform(projection2)).classed("added", function(d2) {
+        return !base.entities[d2.id];
+      }).classed("moved", function(d2) {
+        return base.entities[d2.id] && !(0, import_fast_deep_equal7.default)(graph.entities[d2.id].loc, base.entities[d2.id].loc);
+      }).classed("retagged", function(d2) {
+        return base.entities[d2.id] && !(0, import_fast_deep_equal7.default)(graph.entities[d2.id].tags, base.entities[d2.id].tags);
+      }).call(svgTagClasses());
+      groups.select(".shadow");
+      groups.select(".stroke");
+      groups.select(".icon").attr("xlink:href", function(entity) {
+        var preset = _mainPresetIndex.match(entity, graph);
+        var picon = preset && preset.icon;
+        return picon ? "#" + picon : "";
+      });
+      touchLayer.call(drawTargets, graph, points, filter2);
+    }
+    return drawPoints;
+  }
+
+  // modules/svg/turns.js
+  function svgTurns(projection2, context) {
+    function icon2(turn) {
+      var u2 = turn.u ? "-u" : "";
+      if (turn.no) return "#iD-turn-no" + u2;
+      if (turn.only) return "#iD-turn-only" + u2;
+      return "#iD-turn-yes" + u2;
+    }
+    function drawTurns(selection2, graph, turns) {
+      function turnTransform(d2) {
+        var pxRadius = 50;
+        var toWay = graph.entity(d2.to.way);
+        var toPoints = graph.childNodes(toWay).map(function(n3) {
+          return n3.loc;
+        }).map(projection2);
+        var toLength = geoPathLength(toPoints);
+        var mid = toLength / 2;
+        var toNode = graph.entity(d2.to.node);
+        var toVertex = graph.entity(d2.to.vertex);
+        var a2 = geoAngle(toVertex, toNode, projection2);
+        var o2 = projection2(toVertex.loc);
+        var r2 = d2.u ? 0 : !toWay.__via ? pxRadius : Math.min(mid, pxRadius);
+        return "translate(" + (r2 * Math.cos(a2) + o2[0]) + "," + (r2 * Math.sin(a2) + o2[1]) + ") rotate(" + a2 * 180 / Math.PI + ")";
       }
-      context.map().centerZoomEase(twelfthAvenue, 18, 500);
-      timeout2(function() {
-        var selected, other, padding, box;
-        if (hasWashington) {
-          selected = _t("intro.graph.name.washington-street");
-          other = _t("intro.graph.name.12th-avenue");
-          padding = 60 * Math.pow(2, context.map().zoom() - 18);
-          box = pad(twelfthAvenueEnd, padding, context);
-          box.width *= 3;
-        } else {
-          selected = _t("intro.graph.name.12th-avenue");
-          other = _t("intro.graph.name.washington-street");
-          padding = 200 * Math.pow(2, context.map().zoom() - 18);
-          box = pad(twelfthAvenue, padding, context);
-          box.width /= 2;
-        }
-        reveal(
-          box,
-          helpHtml(
-            "intro.lines.multi_select",
-            { selected, other1: other }
-          ) + " " + helpHtml(
-            "intro.lines.add_to_selection_" + (context.lastPointerType() === "mouse" ? "click" : "touch"),
-            { selected, other2: other }
-          )
-        );
-        context.map().on("move.intro drawn.intro", function() {
-          if (hasWashington) {
-            selected = _t("intro.graph.name.washington-street");
-            other = _t("intro.graph.name.12th-avenue");
-            padding = 60 * Math.pow(2, context.map().zoom() - 18);
-            box = pad(twelfthAvenueEnd, padding, context);
-            box.width *= 3;
-          } else {
-            selected = _t("intro.graph.name.12th-avenue");
-            other = _t("intro.graph.name.washington-street");
-            padding = 200 * Math.pow(2, context.map().zoom() - 18);
-            box = pad(twelfthAvenue, padding, context);
-            box.width /= 2;
-          }
-          reveal(
-            box,
-            helpHtml(
-              "intro.lines.multi_select",
-              { selected, other1: other }
-            ) + " " + helpHtml(
-              "intro.lines.add_to_selection_" + (context.lastPointerType() === "mouse" ? "click" : "touch"),
-              { selected, other2: other }
-            ),
-            { duration: 0 }
-          );
-        });
-        context.on("enter.intro", function() {
-          continueTo(multiSelect);
-        });
-        context.history().on("change.intro", function() {
-          if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-            return continueTo(rightClickIntersection);
-          }
-        });
-      }, 600);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
-    }
-    function multiRightClick() {
-      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-        return continueTo(rightClickIntersection);
-      }
-      var padding = 200 * Math.pow(2, context.map().zoom() - 18);
-      var box = pad(twelfthAvenue, padding, context);
-      var rightClickString = helpHtml("intro.lines.multi_select_success") + helpHtml("intro.lines.multi_" + (context.lastPointerType() === "mouse" ? "rightclick" : "edit_menu_touch"));
-      reveal(box, rightClickString);
-      context.map().on("move.intro drawn.intro", function() {
-        var padding2 = 200 * Math.pow(2, context.map().zoom() - 18);
-        var box2 = pad(twelfthAvenue, padding2, context);
-        reveal(box2, rightClickString, { duration: 0 });
+      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.turns");
+      var touchLayer = selection2.selectAll(".layer-touch.turns");
+      var groups = drawLayer.selectAll("g.turn").data(turns, function(d2) {
+        return d2.key;
       });
-      context.ui().editMenu().on("toggled.intro", function(open) {
-        if (!open)
-          return;
-        timeout2(function() {
-          var ids = context.selectedIDs();
-          if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
-            var node = selectMenuItem(context, "delete").node();
-            if (!node)
-              return;
-            continueTo(multiDelete);
-          } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
-            return continueTo(multiSelect);
-          } else {
-            return continueTo(didSplit);
-          }
-        }, 300);
+      groups.exit().remove();
+      var groupsEnter = groups.enter().append("g").attr("class", function(d2) {
+        return "turn " + d2.key;
       });
-      context.history().on("change.intro", function() {
-        if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-          return continueTo(rightClickIntersection);
-        }
+      var turnsEnter = groupsEnter.filter(function(d2) {
+        return !d2.u;
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.ui().editMenu().on("toggled.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
+      turnsEnter.append("rect").attr("transform", "translate(-22, -12)").attr("width", "44").attr("height", "24");
+      turnsEnter.append("use").attr("transform", "translate(-22, -12)").attr("width", "44").attr("height", "24");
+      var uEnter = groupsEnter.filter(function(d2) {
+        return d2.u;
+      });
+      uEnter.append("circle").attr("r", "16");
+      uEnter.append("use").attr("transform", "translate(-16, -16)").attr("width", "32").attr("height", "32");
+      groups = groups.merge(groupsEnter).attr("opacity", function(d2) {
+        return d2.direct === false ? "0.7" : null;
+      }).attr("transform", turnTransform);
+      groups.select("use").attr("xlink:href", icon2);
+      groups.select("rect");
+      groups.select("circle");
+      var fillClass = context.getDebug("target") ? "pink " : "nocolor ";
+      groups = touchLayer.selectAll("g.turn").data(turns, function(d2) {
+        return d2.key;
+      });
+      groups.exit().remove();
+      groupsEnter = groups.enter().append("g").attr("class", function(d2) {
+        return "turn " + d2.key;
+      });
+      turnsEnter = groupsEnter.filter(function(d2) {
+        return !d2.u;
+      });
+      turnsEnter.append("rect").attr("class", "target " + fillClass).attr("transform", "translate(-22, -12)").attr("width", "44").attr("height", "24");
+      uEnter = groupsEnter.filter(function(d2) {
+        return d2.u;
+      });
+      uEnter.append("circle").attr("class", "target " + fillClass).attr("r", "16");
+      groups = groups.merge(groupsEnter).attr("transform", turnTransform);
+      groups.select("rect");
+      groups.select("circle");
+      return this;
     }
-    function multiDelete() {
-      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
-        return continueTo(rightClickIntersection);
+    return drawTurns;
+  }
+
+  // modules/svg/vertices.js
+  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]
+    };
+    var _currHoverTarget;
+    var _currPersistent = {};
+    var _currHover = {};
+    var _prevHover = {};
+    var _currSelected = {};
+    var _prevSelected = {};
+    var _radii = {};
+    function sortY(a2, b2) {
+      return b2.loc[1] - a2.loc[1];
+    }
+    function fastEntityKey(d2) {
+      var mode = context.mode();
+      var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
+      return isMoving ? d2.id : osmEntity.key(d2);
+    }
+    function draw(selection2, graph, vertices, sets2, filter2) {
+      sets2 = sets2 || { selected: {}, important: {}, hovered: {} };
+      var icons = {};
+      var directions = {};
+      var wireframe = context.surface().classed("fill-wireframe");
+      var zoom = geoScaleToZoom(projection2.scale());
+      var z2 = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
+      var activeID = context.activeID();
+      var base = context.history().base();
+      function getIcon(d2) {
+        var entity = graph.entity(d2.id);
+        if (entity.id in icons) return icons[entity.id];
+        icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
+        return icons[entity.id];
       }
-      var node = selectMenuItem(context, "delete").node();
-      if (!node)
-        return continueTo(multiRightClick);
-      reveal(
-        ".edit-menu",
-        helpHtml("intro.lines.multi_delete"),
-        { padding: 50 }
-      );
-      context.map().on("move.intro drawn.intro", function() {
-        reveal(
-          ".edit-menu",
-          helpHtml("intro.lines.multi_delete"),
-          { duration: 0, padding: 50 }
-        );
+      function getDirections(entity) {
+        if (entity.id in directions) return directions[entity.id];
+        var angles = entity.directions(graph, projection2);
+        directions[entity.id] = angles.length ? angles : false;
+        return angles;
+      }
+      function updateAttributes(selection3) {
+        ["shadow", "stroke", "fill"].forEach(function(klass) {
+          var rads = radiuses[klass];
+          selection3.selectAll("." + klass).each(function(entity) {
+            var i3 = z2 && getIcon(entity);
+            var r2 = rads[i3 ? 3 : z2];
+            if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
+              r2 += 1.5;
+            }
+            if (klass === "shadow") {
+              _radii[entity.id] = r2;
+            }
+            select_default2(this).attr("r", r2).attr("visibility", i3 && klass === "fill" ? "hidden" : null);
+          });
+        });
+      }
+      vertices.sort(sortY);
+      var groups = selection2.selectAll("g.vertex").filter(filter2).data(vertices, fastEntityKey);
+      groups.exit().remove();
+      var enter = groups.enter().append("g").attr("class", function(d2) {
+        return "node vertex " + d2.id;
+      }).order();
+      enter.append("circle").attr("class", "shadow");
+      enter.append("circle").attr("class", "stroke");
+      enter.filter(function(d2) {
+        return d2.hasInterestingTags();
+      }).append("circle").attr("class", "fill");
+      groups = groups.merge(enter).attr("transform", svgPointTransform(projection2)).classed("sibling", function(d2) {
+        return d2.id in sets2.selected;
+      }).classed("shared", function(d2) {
+        return graph.isShared(d2);
+      }).classed("endpoint", function(d2) {
+        return d2.isEndpoint(graph);
+      }).classed("added", function(d2) {
+        return !base.entities[d2.id];
+      }).classed("moved", function(d2) {
+        return base.entities[d2.id] && !(0, import_fast_deep_equal8.default)(graph.entities[d2.id].loc, base.entities[d2.id].loc);
+      }).classed("retagged", function(d2) {
+        return base.entities[d2.id] && !(0, import_fast_deep_equal8.default)(graph.entities[d2.id].tags, base.entities[d2.id].tags);
+      }).call(svgTagClasses()).call(updateAttributes);
+      var iconUse = groups.selectAll(".icon").data(function data(d2) {
+        return zoom >= 17 && getIcon(d2) ? [d2] : [];
+      }, fastEntityKey);
+      iconUse.exit().remove();
+      iconUse.enter().append("use").attr("class", "icon").attr("width", "12px").attr("height", "12px").attr("transform", "translate(-6, -6)").attr("xlink:href", function(d2) {
+        var picon = getIcon(d2);
+        return picon ? "#" + picon : "";
       });
-      context.on("exit.intro", function() {
-        if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
-          return continueTo(multiSelect);
-        }
+      var dgroups = groups.selectAll(".viewfieldgroup").data(function data(d2) {
+        return zoom >= 18 && getDirections(d2) ? [d2] : [];
+      }, fastEntityKey);
+      dgroups.exit().remove();
+      dgroups = dgroups.enter().insert("g", ".shadow").attr("class", "viewfieldgroup").merge(dgroups);
+      var viewfields = dgroups.selectAll(".viewfield").data(getDirections, function key(d2) {
+        return osmEntity.key(d2);
       });
-      context.history().on("change.intro", function() {
-        if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
-          continueTo(retryDelete);
+      viewfields.exit().remove();
+      viewfields.enter().append("path").attr("class", "viewfield").attr("d", "M0,0H0").merge(viewfields).attr("marker-start", "url(#ideditor-viewfield-marker" + (wireframe ? "-wireframe" : "") + ")").attr("transform", function(d2) {
+        return "rotate(" + d2 + ")";
+      });
+    }
+    function drawTargets(selection2, graph, entities, filter2) {
+      var targetClass = context.getDebug("target") ? "pink " : "nocolor ";
+      var nopeClass = context.getDebug("target") ? "red " : "nocolor ";
+      var getTransform = svgPointTransform(projection2).geojson;
+      var activeID = context.activeID();
+      var data = { targets: [], nopes: [] };
+      entities.forEach(function(node) {
+        if (activeID === node.id) return;
+        var vertexType = svgPassiveVertex(node, graph, activeID);
+        if (vertexType !== 0) {
+          data.targets.push({
+            type: "Feature",
+            id: node.id,
+            properties: {
+              target: true,
+              entity: node
+            },
+            geometry: node.asGeoJSON()
+          });
         } else {
-          continueTo(play);
+          data.nopes.push({
+            type: "Feature",
+            id: node.id + "-nope",
+            properties: {
+              nope: true,
+              target: true,
+              entity: node
+            },
+            geometry: node.asGeoJSON()
+          });
         }
       });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("exit.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
+      var targets = selection2.selectAll(".vertex.target-allowed").filter(function(d2) {
+        return filter2(d2.properties.entity);
+      }).data(data.targets, function key(d2) {
+        return d2.id;
+      });
+      targets.exit().remove();
+      targets.enter().append("circle").attr("r", function(d2) {
+        return _radii[d2.id] || radiuses.shadow[3];
+      }).merge(targets).attr("class", function(d2) {
+        return "node vertex target target-allowed " + targetClass + d2.id;
+      }).attr("transform", getTransform);
+      var nopes = selection2.selectAll(".vertex.target-nope").filter(function(d2) {
+        return filter2(d2.properties.entity);
+      }).data(data.nopes, function key(d2) {
+        return d2.id;
+      });
+      nopes.exit().remove();
+      nopes.enter().append("circle").attr("r", function(d2) {
+        return _radii[d2.properties.entity.id] || radiuses.shadow[3];
+      }).merge(nopes).attr("class", function(d2) {
+        return "node vertex target target-nope " + nopeClass + d2.id;
+      }).attr("transform", getTransform);
     }
-    function retryDelete() {
-      context.enter(modeBrowse(context));
-      var padding = 200 * Math.pow(2, context.map().zoom() - 18);
-      var box = pad(twelfthAvenue, padding, context);
-      reveal(box, helpHtml("intro.lines.retry_delete"), {
-        buttonText: _t.html("intro.ok"),
-        buttonCallback: function() {
-          continueTo(multiSelect);
+    function renderAsVertex(entity, graph, wireframe, zoom) {
+      var geometry = entity.geometry(graph);
+      return geometry === "vertex" || geometry === "point" && (wireframe || zoom >= 18 && entity.directions(graph, projection2).length);
+    }
+    function isEditedNode(node, base, head) {
+      var baseNode = base.entities[node.id];
+      var headNode = head.entities[node.id];
+      return !headNode || !baseNode || !(0, import_fast_deep_equal8.default)(headNode.tags, baseNode.tags) || !(0, import_fast_deep_equal8.default)(headNode.loc, baseNode.loc);
+    }
+    function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
+      var results = {};
+      var seenIds = {};
+      function addChildVertices(entity) {
+        if (seenIds[entity.id]) return;
+        seenIds[entity.id] = true;
+        var geometry = entity.geometry(graph);
+        if (!context.features().isHiddenFeature(entity, graph, geometry)) {
+          var i3;
+          if (entity.type === "way") {
+            for (i3 = 0; i3 < entity.nodes.length; i3++) {
+              var child = graph.hasEntity(entity.nodes[i3]);
+              if (child) {
+                addChildVertices(child);
+              }
+            }
+          } else if (entity.type === "relation") {
+            for (i3 = 0; i3 < entity.members.length; i3++) {
+              var member = graph.hasEntity(entity.members[i3].id);
+              if (member) {
+                addChildVertices(member);
+              }
+            }
+          } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
+            results[entity.id] = entity;
+          }
         }
-      });
-      function continueTo(nextStep) {
-        nextStep();
       }
-    }
-    function play() {
-      dispatch10.call("done");
-      reveal(
-        ".ideditor",
-        helpHtml("intro.lines.play", { next: _t("intro.buildings.title") }),
-        {
-          tooltipBox: ".intro-nav-wrap .chapter-building",
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            reveal(".ideditor");
+      ids.forEach(function(id2) {
+        var entity = graph.hasEntity(id2);
+        if (!entity) return;
+        if (entity.type === "node") {
+          if (renderAsVertex(entity, graph, wireframe, zoom)) {
+            results[entity.id] = entity;
+            graph.parentWays(entity).forEach(function(entity2) {
+              addChildVertices(entity2);
+            });
           }
+        } else {
+          addChildVertices(entity);
         }
-      );
+      });
+      return results;
     }
-    chapter.enter = function() {
-      addLine();
-    };
-    chapter.exit = function() {
-      timeouts.forEach(window.clearTimeout);
-      select_default2(window).on("pointerdown.intro mousedown.intro", null, true);
-      context.on("enter.intro exit.intro", null);
-      context.map().on("move.intro drawn.intro", null);
-      context.history().on("change.intro", null);
-      context.container().select(".inspector-wrap").on("wheel.intro", null);
-      context.container().select(".preset-list-button").on("click.intro", null);
+    function drawVertices(selection2, graph, entities, filter2, extent, fullRedraw) {
+      var wireframe = context.surface().classed("fill-wireframe");
+      var visualDiff = context.surface().classed("highlight-edited");
+      var zoom = geoScaleToZoom(projection2.scale());
+      var mode = context.mode();
+      var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
+      var base = context.history().base();
+      var drawLayer = selection2.selectAll(".layer-osm.points .points-group.vertices");
+      var touchLayer = selection2.selectAll(".layer-touch.points");
+      if (fullRedraw) {
+        _currPersistent = {};
+        _radii = {};
+      }
+      for (var i3 = 0; i3 < entities.length; i3++) {
+        var entity = entities[i3];
+        var geometry = entity.geometry(graph);
+        var keep = false;
+        if (geometry === "point" && renderAsVertex(entity, graph, wireframe, zoom)) {
+          _currPersistent[entity.id] = entity;
+          keep = true;
+        } else if (geometry === "vertex" && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
+          _currPersistent[entity.id] = entity;
+          keep = true;
+        }
+        if (!keep && !fullRedraw) {
+          delete _currPersistent[entity.id];
+        }
+      }
+      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(d2) {
+        return d2.id in _currPersistent || d2.id in _currSelected || d2.id in _currHover || filter2(d2);
+      };
+      drawLayer.call(draw, graph, currentVisible(all), sets2, filterRendered);
+      var filterTouch = function(d2) {
+        return isMoving ? true : filterRendered(d2);
+      };
+      touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
+      function currentVisible(which) {
+        return Object.keys(which).map(graph.hasEntity, graph).filter(function(entity2) {
+          return entity2 && entity2.intersects(extent, graph);
+        });
+      }
+    }
+    drawVertices.drawSelected = function(selection2, graph, extent) {
+      var wireframe = context.surface().classed("fill-wireframe");
+      var zoom = geoScaleToZoom(projection2.scale());
+      _prevSelected = _currSelected || {};
+      if (context.map().isInWideSelection()) {
+        _currSelected = {};
+        context.selectedIDs().forEach(function(id2) {
+          var entity = graph.hasEntity(id2);
+          if (!entity) return;
+          if (entity.type === "node") {
+            if (renderAsVertex(entity, graph, wireframe, zoom)) {
+              _currSelected[entity.id] = entity;
+            }
+          }
+        });
+      } else {
+        _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
+      }
+      var filter2 = function(d2) {
+        return d2.id in _prevSelected;
+      };
+      drawVertices(selection2, graph, Object.values(_prevSelected), filter2, extent, false);
     };
-    chapter.restart = function() {
-      chapter.exit();
-      chapter.enter();
+    drawVertices.drawHover = function(selection2, graph, target, extent) {
+      if (target === _currHoverTarget) return;
+      var wireframe = context.surface().classed("fill-wireframe");
+      var zoom = geoScaleToZoom(projection2.scale());
+      _prevHover = _currHover || {};
+      _currHoverTarget = target;
+      var entity = target && target.properties && target.properties.entity;
+      if (entity) {
+        _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
+      } else {
+        _currHover = {};
+      }
+      var filter2 = function(d2) {
+        return d2.id in _prevHover;
+      };
+      drawVertices(selection2, graph, Object.values(_prevHover), filter2, extent, false);
     };
-    return utilRebind(chapter, dispatch10, "on");
+    return drawVertices;
   }
 
-  // modules/ui/intro/building.js
-  function uiIntroBuilding(context, reveal) {
-    var dispatch10 = dispatch_default("done");
-    var house = [-85.62815, 41.95638];
-    var tank = [-85.62732, 41.95347];
-    var buildingCatetory = _mainPresetIndex.item("category-building");
-    var housePreset = _mainPresetIndex.item("building/house");
-    var tankPreset = _mainPresetIndex.item("man_made/storage_tank");
-    var timeouts = [];
-    var _houseID = null;
-    var _tankID = null;
-    var chapter = {
-      title: "intro.buildings.title"
+  // modules/ui/length_indicator.js
+  function uiLengthIndicator(maxChars) {
+    var _wrap = select_default2(null);
+    var _tooltip = uiPopover("tooltip max-length-warning").placement("bottom").hasArrow(true).content(() => (selection2) => {
+      selection2.text("");
+      selection2.call(svgIcon("#iD-icon-alert", "inline"));
+      selection2.call(_t.append("inspector.max_length_reached", { maxChars }));
+    });
+    var _silent = false;
+    var lengthIndicator = function(selection2) {
+      _wrap = selection2.selectAll("span.length-indicator-wrap").data([0]);
+      _wrap = _wrap.enter().append("span").merge(_wrap).classed("length-indicator-wrap", true);
+      selection2.call(_tooltip);
+    };
+    lengthIndicator.update = function(val) {
+      const strLen = utilUnicodeCharsCount(utilCleanOsmString(val, Number.POSITIVE_INFINITY));
+      let indicator = _wrap.selectAll("span.length-indicator").data([strLen]);
+      indicator.enter().append("span").merge(indicator).classed("length-indicator", true).classed("limit-reached", (d2) => d2 > maxChars).style("border-right-width", (d2) => "".concat(Math.abs(maxChars - d2) * 2, "px")).style("margin-right", (d2) => d2 > maxChars ? "".concat((maxChars - d2) * 2, "px") : 0).style("opacity", (d2) => d2 > maxChars * 0.8 ? Math.min(1, (d2 / maxChars - 0.8) / (1 - 0.8)) : 0).style("pointer-events", (d2) => d2 > maxChars * 0.8 ? null : "none");
+      if (_silent) return;
+      if (strLen > maxChars) {
+        _tooltip.show();
+      } else {
+        _tooltip.hide();
+      }
+    };
+    lengthIndicator.silent = function(val) {
+      if (!arguments.length) return _silent;
+      _silent = val;
+      return lengthIndicator;
     };
-    function timeout2(f2, t) {
-      timeouts.push(window.setTimeout(f2, t));
+    return lengthIndicator;
+  }
+
+  // modules/ui/fields/combo.js
+  function uiFieldCombo(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var _isMulti = field.type === "multiCombo" || field.type === "manyCombo";
+    var _isNetwork = field.type === "networkCombo";
+    var _isSemi = field.type === "semiCombo";
+    var _showTagInfoSuggestions = field.type !== "manyCombo" && field.autoSuggestions !== false;
+    var _allowCustomValues = field.type !== "manyCombo" && field.customValues !== false;
+    var _snake_case = field.snake_case || field.snake_case === void 0;
+    var _combobox = uiCombobox(context, "combo-" + field.safeid).caseSensitive(field.caseSensitive).minItems(1);
+    var _container = select_default2(null);
+    var _inputWrap = select_default2(null);
+    var _input = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
+    var _comboData = [];
+    var _multiData = [];
+    var _entityIDs = [];
+    var _tags;
+    var _countryCode;
+    var _staticPlaceholder;
+    var _dataDeprecated = [];
+    _mainFileFetcher.get("deprecated").then(function(d2) {
+      _dataDeprecated = d2;
+    }).catch(function() {
+    });
+    if (_isMulti && field.key && /[^:]$/.test(field.key)) {
+      field.key += ":";
     }
-    function eventCancel(d3_event) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
+    function snake(s2) {
+      return s2.replace(/\s+/g, "_");
     }
-    function revealHouse(center, text2, options2) {
-      var padding = 160 * Math.pow(2, context.map().zoom() - 20);
-      var box = pad(center, padding, context);
-      reveal(box, text2, options2);
+    function clean2(s2) {
+      return s2.split(";").map(function(s3) {
+        return s3.trim();
+      }).join(";");
     }
-    function revealTank(center, text2, options2) {
-      var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
-      var box = pad(center, padding, context);
-      reveal(box, text2, options2);
+    function tagValue(dval) {
+      dval = clean2(dval || "");
+      var found = getOptions(true).find(function(o2) {
+        return o2.key && clean2(o2.value) === dval;
+      });
+      if (found) return found.key;
+      if (field.type === "typeCombo" && !dval) {
+        return "yes";
+      }
+      return restrictTagValueSpelling(dval) || void 0;
     }
-    function addHouse() {
-      context.enter(modeBrowse(context));
-      context.history().reset("initial");
-      _houseID = null;
-      var msec = transitionTime(house, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
+    function restrictTagValueSpelling(dval) {
+      if (_snake_case) {
+        dval = snake(dval);
       }
-      context.map().centerZoomEase(house, 19, msec);
-      timeout2(function() {
-        var tooltip = reveal(
-          "button.add-area",
-          helpHtml("intro.buildings.add_building")
-        );
-        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-buildings");
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-area")
-            return;
-          continueTo(startHouse);
-        });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        nextStep();
+      if (!field.caseSensitive) {
+        dval = dval.toLowerCase();
       }
+      return dval;
     }
-    function startHouse() {
-      if (context.mode().id !== "add-area") {
-        return continueTo(addHouse);
+    function getLabelId(field2, v2) {
+      return field2.hasTextForStringId("options.".concat(v2, ".title")) ? "options.".concat(v2, ".title") : "options.".concat(v2);
+    }
+    function displayValue(tval) {
+      tval = tval || "";
+      var stringsField = field.resolveReference("stringsCrossReference");
+      const labelId = getLabelId(stringsField, tval);
+      if (stringsField.hasTextForStringId(labelId)) {
+        return stringsField.t(labelId, { default: tval });
       }
-      _houseID = null;
-      context.map().zoomEase(20, 500);
-      timeout2(function() {
-        var startString = helpHtml("intro.buildings.start_building") + helpHtml("intro.buildings.building_corner_" + (context.lastPointerType() === "mouse" ? "click" : "tap"));
-        revealHouse(house, startString);
-        context.map().on("move.intro drawn.intro", function() {
-          revealHouse(house, startString, { duration: 0 });
-        });
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "draw-area")
-            return chapter.restart();
-          continueTo(continueHouse);
-        });
-      }, 550);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
+      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
+        return "";
       }
+      return tval;
     }
-    function continueHouse() {
-      if (context.mode().id !== "draw-area") {
-        return continueTo(addHouse);
+    function renderValue(tval) {
+      tval = tval || "";
+      var stringsField = field.resolveReference("stringsCrossReference");
+      const labelId = getLabelId(stringsField, tval);
+      if (stringsField.hasTextForStringId(labelId)) {
+        return stringsField.t.append(labelId, { default: tval });
       }
-      _houseID = null;
-      var continueString = helpHtml("intro.buildings.continue_building") + "{br}" + helpHtml("intro.areas.finish_area_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.buildings.finish_building");
-      revealHouse(house, continueString);
-      context.map().on("move.intro drawn.intro", function() {
-        revealHouse(house, continueString, { duration: 0 });
+      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
+        tval = "";
+      }
+      return (selection2) => selection2.text(tval);
+    }
+    function objectDifference(a2, b2) {
+      return a2.filter(function(d1) {
+        return !b2.some(function(d2) {
+          return d1.value === d2.value;
+        });
       });
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "draw-area") {
-          return;
-        } else if (mode.id === "select") {
-          var graph = context.graph();
-          var way = context.entity(context.selectedIDs()[0]);
-          var nodes = graph.childNodes(way);
-          var points = utilArrayUniq(nodes).map(function(n2) {
-            return context.projection(n2.loc);
-          });
-          if (isMostlySquare(points)) {
-            _houseID = way.id;
-            return continueTo(chooseCategoryBuilding);
-          } else {
-            return continueTo(retryHouse);
-          }
-        } else {
-          return chapter.restart();
-        }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
-      }
     }
-    function retryHouse() {
-      var onClick = function() {
-        continueTo(addHouse);
-      };
-      revealHouse(
-        house,
-        helpHtml("intro.buildings.retry_building"),
-        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-      );
-      context.map().on("move.intro drawn.intro", function() {
-        revealHouse(
-          house,
-          helpHtml("intro.buildings.retry_building"),
-          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
-        );
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        nextStep();
+    function initCombo(selection2, attachTo) {
+      if (!_allowCustomValues) {
+        selection2.attr("readonly", "readonly");
       }
-    }
-    function chooseCategoryBuilding() {
-      if (!_houseID || !context.hasEntity(_houseID)) {
-        return addHouse();
+      if (_showTagInfoSuggestions && services.taginfo) {
+        selection2.call(_combobox.fetcher(setTaginfoValues), attachTo);
+        setTaginfoValues("", setPlaceholder);
+      } else {
+        selection2.call(_combobox, attachTo);
+        setTimeout(() => setStaticValues(setPlaceholder), 0);
       }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _houseID) {
-        context.enter(modeSelect(context, [_houseID]));
+    }
+    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);
       }
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      timeout2(function() {
-        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
-        var button = context.container().select(".preset-category-building .preset-list-button");
-        reveal(
-          button.node(),
-          helpHtml("intro.buildings.choose_category_building", { category: buildingCatetory.name() })
-        );
-        button.on("click.intro", function() {
-          button.on("click.intro", null);
-          continueTo(choosePresetHouse);
-        });
-      }, 400);
-      context.on("enter.intro", function(mode) {
-        if (!_houseID || !context.hasEntity(_houseID)) {
-          return continueTo(addHouse);
-        }
-        var ids2 = context.selectedIDs();
-        if (mode.id !== "select" || !ids2.length || ids2[0] !== _houseID) {
-          return continueTo(chooseCategoryBuilding);
-        }
+      return options2.map(function(v2) {
+        const labelId = getLabelId(stringsField, v2);
+        return {
+          key: v2,
+          value: stringsField.t(labelId, { default: v2 }),
+          title: stringsField.t("options.".concat(v2, ".description"), { default: v2 }),
+          display: addComboboxIcons(stringsField.t.append(labelId, { default: v2 }), v2),
+          klass: stringsField.hasTextForStringId(labelId) ? "" : "raw-option"
+        };
       });
-      function continueTo(nextStep) {
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.container().select(".preset-list-button").on("click.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
+    }
+    function hasStaticValues() {
+      return getOptions().length > 0;
+    }
+    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 choosePresetHouse() {
-      if (!_houseID || !context.hasEntity(_houseID)) {
-        return addHouse();
+    function setTaginfoValues(q2, callback) {
+      var queryFilter = (d2) => d2.value.toLowerCase().includes(q2.toLowerCase()) || d2.key.toLowerCase().includes(q2.toLowerCase());
+      if (hasStaticValues()) {
+        setStaticValues(callback, queryFilter);
       }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _houseID) {
-        context.enter(modeSelect(context, [_houseID]));
+      var stringsField = field.resolveReference("stringsCrossReference");
+      var fn = _isMulti ? "multikeys" : "values";
+      var query = (_isMulti ? field.key : "") + q2;
+      var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q2.toLowerCase()) === 0;
+      if (hasCountryPrefix) {
+        query = _countryCode + ":";
       }
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      timeout2(function() {
-        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
-        var button = context.container().select(".preset-building-house .preset-list-button");
-        reveal(
-          button.node(),
-          helpHtml("intro.buildings.choose_preset_house", { preset: housePreset.name() }),
-          { duration: 300 }
-        );
-        button.on("click.intro", function() {
-          button.on("click.intro", null);
-          continueTo(closeEditorHouse);
+      var params = {
+        debounce: q2 !== "",
+        key: field.key,
+        query
+      };
+      if (_entityIDs.length) {
+        params.geometry = context.graph().geometry(_entityIDs[0]);
+      }
+      services.taginfo[fn](params, function(err, data) {
+        if (err) return;
+        data = data.filter((d2) => field.type !== "typeCombo" || d2.value !== "yes");
+        data = data.filter((d2) => {
+          var value = d2.value;
+          if (_isMulti) {
+            value = value.slice(field.key.length);
+          }
+          return value === restrictTagValueSpelling(value);
         });
-      }, 400);
-      context.on("enter.intro", function(mode) {
-        if (!_houseID || !context.hasEntity(_houseID)) {
-          return continueTo(addHouse);
+        var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
+        if (deprecatedValues) {
+          data = data.filter((d2) => !deprecatedValues.includes(d2.value));
         }
-        var ids2 = context.selectedIDs();
-        if (mode.id !== "select" || !ids2.length || ids2[0] !== _houseID) {
-          return continueTo(chooseCategoryBuilding);
+        if (hasCountryPrefix) {
+          data = data.filter((d2) => d2.value.toLowerCase().indexOf(_countryCode + ":") === 0);
         }
+        const additionalOptions = (field.options || stringsField.options || []).filter((v2) => !data.some((dv) => dv.value === (_isMulti ? field.key + v2 : v2))).map((v2) => ({ value: v2 }));
+        _container.classed("empty-combobox", data.length === 0);
+        _comboData = data.concat(additionalOptions).map(function(d2) {
+          var v2 = d2.value;
+          if (_isMulti) v2 = v2.replace(field.key, "");
+          const labelId = getLabelId(stringsField, v2);
+          var isLocalizable = stringsField.hasTextForStringId(labelId);
+          var label = stringsField.t(labelId, { default: v2 });
+          return {
+            key: v2,
+            value: label,
+            title: stringsField.t("options.".concat(v2, ".description"), { default: isLocalizable ? v2 : d2.title !== label ? d2.title : "" }),
+            display: addComboboxIcons(stringsField.t.append(labelId, { default: v2 }), v2),
+            klass: isLocalizable ? "" : "raw-option"
+          };
+        });
+        _comboData = _comboData.filter(queryFilter);
+        _comboData = objectDifference(_comboData, _multiData);
+        if (callback) callback(_comboData, hasStaticValues());
       });
-      function continueTo(nextStep) {
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.container().select(".preset-list-button").on("click.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
-      }
     }
-    function closeEditorHouse() {
-      if (!_houseID || !context.hasEntity(_houseID)) {
-        return addHouse();
-      }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _houseID) {
-        context.enter(modeSelect(context, [_houseID]));
-      }
-      context.history().checkpoint("hasHouse");
-      context.on("exit.intro", function() {
-        continueTo(rightClickHouse);
-      });
-      timeout2(function() {
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.buildings.close", { button: { html: icon("#iD-icon-close", "inline") } })
-        );
-      }, 500);
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
+    function addComboboxIcons(disp, value) {
+      const iconsField = field.resolveReference("iconsCrossReference");
+      if (iconsField.icons) {
+        return function(selection2) {
+          var span = selection2.insert("span", ":first-child").attr("class", "tag-value-icon");
+          if (iconsField.icons[value]) {
+            span.call(svgIcon("#".concat(iconsField.icons[value])));
+          }
+          disp.call(this, selection2);
+        };
       }
+      return disp;
     }
-    function rightClickHouse() {
-      if (!_houseID)
-        return chapter.restart();
-      context.enter(modeBrowse(context));
-      context.history().reset("hasHouse");
-      var zoom = context.map().zoom();
-      if (zoom < 20) {
-        zoom = 20;
+    function setPlaceholder(values) {
+      if (_isMulti || _isSemi) {
+        _staticPlaceholder = field.placeholder() || _t("inspector.add");
+      } else {
+        var vals = values.map(function(d2) {
+          return d2.value;
+        }).filter(function(s2) {
+          return s2.length < 20;
+        });
+        var placeholders = vals.length > 1 ? vals : values.map(function(d2) {
+          return d2.key;
+        });
+        _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(", ");
       }
-      context.map().centerZoomEase(house, zoom, 500);
-      context.on("enter.intro", function(mode) {
-        if (mode.id !== "select")
-          return;
-        var ids = context.selectedIDs();
-        if (ids.length !== 1 || ids[0] !== _houseID)
-          return;
-        timeout2(function() {
-          var node = selectMenuItem(context, "orthogonalize").node();
-          if (!node)
-            return;
-          continueTo(clickSquare);
-        }, 50);
-      });
-      context.map().on("move.intro drawn.intro", function() {
-        var rightclickString = helpHtml("intro.buildings." + (context.lastPointerType() === "mouse" ? "rightclick_building" : "edit_menu_building_touch"));
-        revealHouse(house, rightclickString, { duration: 0 });
-      });
-      context.history().on("change.intro", function() {
-        continueTo(rightClickHouse);
-      });
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+      if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
+        _staticPlaceholder += "\u2026";
       }
-    }
-    function clickSquare() {
-      if (!_houseID)
-        return chapter.restart();
-      var entity = context.hasEntity(_houseID);
-      if (!entity)
-        return continueTo(rightClickHouse);
-      var node = selectMenuItem(context, "orthogonalize").node();
-      if (!node) {
-        return continueTo(rightClickHouse);
+      var ph;
+      if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
+        ph = _t("inspector.multiple_values");
+      } else {
+        ph = _staticPlaceholder;
       }
-      var wasChanged = false;
-      reveal(
-        ".edit-menu",
-        helpHtml("intro.buildings.square_building"),
-        { padding: 50 }
-      );
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "browse") {
-          continueTo(rightClickHouse);
-        } else if (mode.id === "move" || mode.id === "rotate") {
-          continueTo(retryClickSquare);
+      _container.selectAll("input").attr("placeholder", ph);
+      var hideAdd = !_allowCustomValues && !values.length;
+      _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
+    }
+    function change() {
+      var t2 = {};
+      var val;
+      if (_isMulti || _isSemi) {
+        var vals;
+        if (_isMulti) {
+          vals = [tagValue(utilGetSetValue(_input))];
+        } else if (_isSemi) {
+          val = tagValue(utilGetSetValue(_input)) || "";
+          val = val.replace(/,/g, ";");
+          vals = val.split(";");
         }
-      });
-      context.map().on("move.intro", function() {
-        var node2 = selectMenuItem(context, "orthogonalize").node();
-        if (!wasChanged && !node2) {
-          return continueTo(rightClickHouse);
+        vals = vals.filter(Boolean);
+        if (!vals.length) return;
+        _container.classed("active", false);
+        utilGetSetValue(_input, "");
+        if (_isMulti) {
+          utilArrayUniq(vals).forEach(function(v2) {
+            var key = (field.key || "") + v2;
+            if (_tags) {
+              var old = _tags[key];
+              if (typeof old === "string" && old.toLowerCase() !== "no") return;
+            }
+            key = context.cleanTagKey(key);
+            field.keys.push(key);
+            t2[key] = "yes";
+          });
+        } else if (_isSemi) {
+          var arr = _multiData.map(function(d2) {
+            return d2.key;
+          });
+          arr = arr.concat(vals);
+          t2[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(";"));
         }
-        reveal(
-          ".edit-menu",
-          helpHtml("intro.buildings.square_building"),
-          { duration: 0, padding: 50 }
-        );
-      });
-      context.history().on("change.intro", function() {
-        wasChanged = true;
-        context.history().on("change.intro", null);
-        timeout2(function() {
-          if (context.history().undoAnnotation() === _t("operations.orthogonalize.annotation.feature", { n: 1 })) {
-            continueTo(doneSquare);
-          } else {
-            continueTo(retryClickSquare);
-          }
-        }, 500);
-      });
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.map().on("move.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+        window.setTimeout(function() {
+          _input.node().focus();
+        }, 10);
+      } else {
+        var rawValue = utilGetSetValue(_input);
+        if (!rawValue && Array.isArray(_tags[field.key])) return;
+        val = context.cleanTagValue(tagValue(rawValue));
+        t2[field.key] = val || void 0;
       }
+      dispatch14.call("change", this, t2);
     }
-    function retryClickSquare() {
-      context.enter(modeBrowse(context));
-      revealHouse(house, helpHtml("intro.buildings.retry_square"), {
-        buttonText: _t.html("intro.ok"),
-        buttonCallback: function() {
-          continueTo(rightClickHouse);
-        }
-      });
-      function continueTo(nextStep) {
-        nextStep();
+    function removeMultikey(d3_event, d2) {
+      d3_event.preventDefault();
+      d3_event.stopPropagation();
+      var t2 = {};
+      if (_isMulti) {
+        t2[d2.key] = void 0;
+      } else if (_isSemi) {
+        var arr = _multiData.map(function(md) {
+          return md.key === d2.key ? null : md.key;
+        }).filter(Boolean);
+        arr = utilArrayUniq(arr);
+        t2[field.key] = arr.length ? arr.join(";") : void 0;
+        _lengthIndicator.update(t2[field.key]);
       }
+      dispatch14.call("change", this, t2);
     }
-    function doneSquare() {
-      context.history().checkpoint("doneSquare");
-      revealHouse(house, helpHtml("intro.buildings.done_square"), {
-        buttonText: _t.html("intro.ok"),
-        buttonCallback: function() {
-          continueTo(addTank);
-        }
-      });
-      function continueTo(nextStep) {
-        nextStep();
+    function invertMultikey(d3_event, d2) {
+      d3_event.preventDefault();
+      d3_event.stopPropagation();
+      var t2 = {};
+      if (_isMulti) {
+        t2[d2.key] = _tags[d2.key] === "yes" ? "no" : "yes";
       }
+      dispatch14.call("change", this, t2);
     }
-    function addTank() {
-      context.enter(modeBrowse(context));
-      context.history().reset("doneSquare");
-      _tankID = null;
-      var msec = transitionTime(tank, context.map().center());
-      if (msec) {
-        reveal(null, null, { duration: 0 });
+    function combo(selection2) {
+      _container = selection2.selectAll(".form-field-input-wrap").data([0]);
+      var type2 = _isMulti || _isSemi ? "multicombo" : "combo";
+      _container = _container.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + type2).merge(_container);
+      if (_isMulti || _isSemi) {
+        _container = _container.selectAll(".chiplist").data([0]);
+        var listClass = "chiplist";
+        if (field.key === "destination" || field.key === "via") {
+          listClass += " full-line-chips";
+        }
+        _container = _container.enter().append("ul").attr("class", listClass).on("click", function() {
+          window.setTimeout(function() {
+            _input.node().focus();
+          }, 10);
+        }).merge(_container);
+        _inputWrap = _container.selectAll(".input-wrap").data([0]);
+        _inputWrap = _inputWrap.enter().append("li").attr("class", "input-wrap").merge(_inputWrap);
+        var hideAdd = !_allowCustomValues && !_comboData.length;
+        _inputWrap.style("display", hideAdd ? "none" : null);
+        _input = _inputWrap.selectAll("input").data([0]);
+      } else {
+        _input = _container.selectAll("input").data([0]);
       }
-      context.map().centerZoomEase(tank, 19.5, msec);
-      timeout2(function() {
-        reveal(
-          "button.add-area",
-          helpHtml("intro.buildings.add_tank")
-        );
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "add-area")
-            return;
-          continueTo(startTank);
-        });
-      }, msec + 100);
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        nextStep();
+      _input = _input.enter().append("input").attr("type", "text").attr("id", field.domId).call(utilNoAuto).call(initCombo, _container).merge(_input);
+      if (_isSemi) {
+        _inputWrap.call(_lengthIndicator);
+      } else if (!_isMulti) {
+        _container.call(_lengthIndicator);
       }
-    }
-    function startTank() {
-      if (context.mode().id !== "add-area") {
-        return continueTo(addTank);
+      if (_isNetwork) {
+        var extent = combinedEntityExtent();
+        var countryCode = extent && iso1A2Code(extent.center());
+        _countryCode = countryCode && countryCode.toLowerCase();
       }
-      _tankID = null;
-      timeout2(function() {
-        var startString = helpHtml("intro.buildings.start_tank") + helpHtml("intro.buildings.tank_edge_" + (context.lastPointerType() === "mouse" ? "click" : "tap"));
-        revealTank(tank, startString);
-        context.map().on("move.intro drawn.intro", function() {
-          revealTank(tank, startString, { duration: 0 });
+      _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:
+            _input.node().blur();
+            d3_event.stopPropagation();
+            break;
+        }
+      });
+      if (_isMulti || _isSemi) {
+        _combobox.on("accept", function() {
+          _input.node().blur();
+          _input.node().focus();
         });
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "draw-area")
-            return chapter.restart();
-          continueTo(continueTank);
+        _input.on("focus", function() {
+          _container.classed("active", true);
         });
-      }, 550);
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
       }
+      _combobox.on("cancel", function() {
+        _input.node().blur();
+      }).on("update", function() {
+        updateIcon(utilGetSetValue(_input));
+      });
     }
-    function continueTank() {
-      if (context.mode().id !== "draw-area") {
-        return continueTo(addTank);
+    function updateIcon(value) {
+      value = tagValue(value);
+      let container = _container;
+      if (field.type === "multiCombo" || field.type === "semiCombo") {
+        container = _container.select(".input-wrap");
       }
-      _tankID = null;
-      var continueString = helpHtml("intro.buildings.continue_tank") + "{br}" + helpHtml("intro.areas.finish_area_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.buildings.finish_tank");
-      revealTank(tank, continueString);
-      context.map().on("move.intro drawn.intro", function() {
-        revealTank(tank, continueString, { duration: 0 });
-      });
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "draw-area") {
-          return;
-        } else if (mode.id === "select") {
-          _tankID = context.selectedIDs()[0];
-          return continueTo(searchPresetTank);
-        } else {
-          return continueTo(addTank);
+      const iconsField = field.resolveReference("iconsCrossReference");
+      if (iconsField.icons) {
+        container.selectAll(".tag-value-icon").remove();
+        if (iconsField.icons[value]) {
+          container.selectAll(".tag-value-icon").data([value]).enter().insert("div", "input").attr("class", "tag-value-icon").call(svgIcon("#".concat(iconsField.icons[value])));
         }
-      });
-      function continueTo(nextStep) {
-        context.map().on("move.intro drawn.intro", null);
-        context.on("enter.intro", null);
-        nextStep();
       }
     }
-    function searchPresetTank() {
-      if (!_tankID || !context.hasEntity(_tankID)) {
-        return addTank();
-      }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _tankID) {
-        context.enter(modeSelect(context, [_tankID]));
-      }
-      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-      timeout2(function() {
-        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
-        context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
-        reveal(
-          ".preset-search-input",
-          helpHtml("intro.buildings.search_tank", { preset: tankPreset.name() })
-        );
-      }, 400);
-      context.on("enter.intro", function(mode) {
-        if (!_tankID || !context.hasEntity(_tankID)) {
-          return continueTo(addTank);
+    combo.tags = function(tags) {
+      _tags = tags;
+      var stringsField = field.resolveReference("stringsCrossReference");
+      var isMixed = Array.isArray(tags[field.key]);
+      var showsValue = (value) => !isMixed && value && !(field.type === "typeCombo" && value === "yes");
+      var isRawValue = (value) => showsValue(value) && !stringsField.hasTextForStringId("options.".concat(value)) && !stringsField.hasTextForStringId("options.".concat(value, ".title"));
+      var isKnownValue = (value) => showsValue(value) && !isRawValue(value);
+      var isReadOnly = !_allowCustomValues;
+      if (_isMulti || _isSemi) {
+        _multiData = [];
+        var maxLength;
+        if (_isMulti) {
+          for (var k2 in tags) {
+            if (field.key && k2.indexOf(field.key) !== 0) continue;
+            if (!field.key && field.keys.indexOf(k2) === -1) continue;
+            var v2 = tags[k2];
+            var suffix = field.key ? k2.slice(field.key.length) : k2;
+            _multiData.push({
+              key: k2,
+              value: displayValue(suffix),
+              display: addComboboxIcons(renderValue(suffix), suffix),
+              state: typeof v2 === "string" ? v2.toLowerCase() : "",
+              isMixed: Array.isArray(v2)
+            });
+          }
+          if (field.key) {
+            field.keys = _multiData.map(function(d2) {
+              return d2.key;
+            });
+            maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
+          } else {
+            maxLength = context.maxCharsForTagKey();
+          }
+        } else if (_isSemi) {
+          var allValues = [];
+          var commonValues;
+          if (Array.isArray(tags[field.key])) {
+            tags[field.key].forEach(function(tagVal) {
+              var thisVals = utilArrayUniq((tagVal || "").split(";")).filter(Boolean);
+              allValues = allValues.concat(thisVals);
+              if (!commonValues) {
+                commonValues = thisVals;
+              } else {
+                commonValues = commonValues.filter((value) => thisVals.includes(value));
+              }
+            });
+            allValues = utilArrayUniq(allValues).filter(Boolean);
+          } else {
+            allValues = utilArrayUniq((tags[field.key] || "").split(";")).filter(Boolean);
+            commonValues = allValues;
+          }
+          _multiData = allValues.map(function(v3) {
+            return {
+              key: v3,
+              value: displayValue(v3),
+              display: addComboboxIcons(renderValue(v3), v3),
+              isMixed: !commonValues.includes(v3)
+            };
+          });
+          var currLength = utilUnicodeCharsCount(commonValues.join(";"));
+          maxLength = context.maxCharsForTagValue() - currLength;
+          if (currLength > 0) {
+            maxLength -= 1;
+          }
         }
-        var ids2 = context.selectedIDs();
-        if (mode.id !== "select" || !ids2.length || ids2[0] !== _tankID) {
-          context.enter(modeSelect(context, [_tankID]));
-          context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
-          context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
-          context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
-          reveal(
-            ".preset-search-input",
-            helpHtml("intro.buildings.search_tank", { preset: tankPreset.name() })
-          );
-          context.history().on("change.intro", null);
+        maxLength = Math.max(0, maxLength);
+        var hideAdd = maxLength <= 0 || !_allowCustomValues && !_comboData.length;
+        _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
+        var allowDragAndDrop = _isSemi && !Array.isArray(tags[field.key]);
+        var chips = _container.selectAll(".chip").data(_multiData);
+        chips.exit().remove();
+        var enter = chips.enter().insert("li", ".input-wrap").attr("class", "chip");
+        enter.append("span");
+        const field_buttons = enter.append("div").attr("class", "field_buttons");
+        field_buttons.append("a").attr("class", "remove");
+        chips = chips.merge(enter).order().classed("raw-value", function(d2) {
+          var k3 = d2.key;
+          if (_isMulti) k3 = k3.replace(field.key, "");
+          return !stringsField.hasTextForStringId("options." + k3);
+        }).classed("draggable", allowDragAndDrop).classed("mixed", function(d2) {
+          return d2.isMixed;
+        }).attr("title", function(d2) {
+          if (d2.isMixed) {
+            return _t("inspector.unshared_value_tooltip");
+          }
+          if (!["yes", "no"].includes(d2.state)) {
+            return d2.state;
+          }
+          return null;
+        }).classed("negated", (d2) => d2.state === "no");
+        if (!_isSemi) {
+          chips.selectAll("input[type=checkbox]").remove();
+          chips.insert("input", "span").attr("type", "checkbox").property("checked", (d2) => d2.state === "yes").property("indeterminate", (d2) => d2.isMixed || !["yes", "no"].includes(d2.state)).on("click", invertMultikey);
         }
-      });
-      function checkPresetSearch() {
-        var first = context.container().select(".preset-list-item:first-child");
-        if (first.classed("preset-man_made-storage_tank")) {
-          reveal(
-            first.select(".preset-list-button").node(),
-            helpHtml("intro.buildings.choose_tank", { preset: tankPreset.name() }),
-            { duration: 300 }
-          );
-          context.container().select(".preset-search-input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
-          context.history().on("change.intro", function() {
-            continueTo(closeEditorTank);
-          });
+        if (allowDragAndDrop) {
+          registerDragAndDrop(chips);
         }
-      }
-      function continueTo(nextStep) {
-        context.container().select(".inspector-wrap").on("wheel.intro", null);
-        context.on("enter.intro", null);
-        context.history().on("change.intro", null);
-        context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
-        nextStep();
-      }
-    }
-    function closeEditorTank() {
-      if (!_tankID || !context.hasEntity(_tankID)) {
-        return addTank();
-      }
-      var ids = context.selectedIDs();
-      if (context.mode().id !== "select" || !ids.length || ids[0] !== _tankID) {
-        context.enter(modeSelect(context, [_tankID]));
-      }
-      context.history().checkpoint("hasTank");
-      context.on("exit.intro", function() {
-        continueTo(rightClickTank);
-      });
-      timeout2(function() {
-        reveal(
-          ".entity-editor-pane",
-          helpHtml("intro.buildings.close", { button: { html: icon("#iD-icon-close", "inline") } })
-        );
-      }, 500);
-      function continueTo(nextStep) {
-        context.on("exit.intro", null);
-        nextStep();
-      }
-    }
-    function rightClickTank() {
-      if (!_tankID)
-        return continueTo(addTank);
-      context.enter(modeBrowse(context));
-      context.history().reset("hasTank");
-      context.map().centerEase(tank, 500);
-      timeout2(function() {
-        context.on("enter.intro", function(mode) {
-          if (mode.id !== "select")
+        chips.each(function(d2) {
+          const selection2 = select_default2(this);
+          const text_span = selection2.select("span");
+          const field_buttons2 = selection2.select(".field_buttons");
+          const clean_value = d2.value.trim();
+          text_span.text("");
+          if (!field_buttons2.select("button").empty()) {
+            field_buttons2.select("button").remove();
+          }
+          if (clean_value.startsWith("https://")) {
+            text_span.text(clean_value);
+            field_buttons2.append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", () => _t("icons.visit_website")).attr("aria-label", () => _t("icons.visit_website")).on("click", function(d3_event) {
+              d3_event.preventDefault();
+              window.open(clean_value, "_blank");
+            });
             return;
-          var ids = context.selectedIDs();
-          if (ids.length !== 1 || ids[0] !== _tankID)
+          }
+          if (d2.display) {
+            d2.display(text_span);
             return;
-          timeout2(function() {
-            var node = selectMenuItem(context, "circularize").node();
-            if (!node)
-              return;
-            continueTo(clickCircle);
-          }, 50);
-        });
-        var rightclickString = helpHtml("intro.buildings." + (context.lastPointerType() === "mouse" ? "rightclick_tank" : "edit_menu_tank_touch"));
-        revealTank(tank, rightclickString);
-        context.map().on("move.intro drawn.intro", function() {
-          revealTank(tank, rightclickString, { duration: 0 });
+          }
+          text_span.text(d2.value);
         });
-        context.history().on("change.intro", function() {
-          continueTo(rightClickTank);
+        chips.select("a.remove").attr("href", "#").on("click", removeMultikey).attr("class", "remove").text("\xD7");
+        updateIcon("");
+      } else {
+        var mixedValues = isMixed && tags[field.key].map(function(val) {
+          return displayValue(val);
+        }).filter(Boolean);
+        utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : "").data([tags[field.key]]).classed("raw-value", isRawValue).classed("known-value", isKnownValue).attr("readonly", isReadOnly ? "readonly" : void 0).attr("title", isMixed ? mixedValues.join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : _staticPlaceholder || "").classed("mixed", isMixed).on("keydown.deleteCapture", function(d3_event) {
+          if (isReadOnly && isKnownValue(tags[field.key]) && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            var t2 = {};
+            t2[field.key] = void 0;
+            dispatch14.call("change", this, t2);
+          }
         });
-      }, 600);
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.map().on("move.intro drawn.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
-      }
-    }
-    function clickCircle() {
-      if (!_tankID)
-        return chapter.restart();
-      var entity = context.hasEntity(_tankID);
-      if (!entity)
-        return continueTo(rightClickTank);
-      var node = selectMenuItem(context, "circularize").node();
-      if (!node) {
-        return continueTo(rightClickTank);
-      }
-      var wasChanged = false;
-      reveal(
-        ".edit-menu",
-        helpHtml("intro.buildings.circle_tank"),
-        { padding: 50 }
-      );
-      context.on("enter.intro", function(mode) {
-        if (mode.id === "browse") {
-          continueTo(rightClickTank);
-        } else if (mode.id === "move" || mode.id === "rotate") {
-          continueTo(retryClickCircle);
+        if (!Array.isArray(tags[field.key])) {
+          updateIcon(tags[field.key]);
         }
-      });
-      context.map().on("move.intro", function() {
-        var node2 = selectMenuItem(context, "circularize").node();
-        if (!wasChanged && !node2) {
-          return continueTo(rightClickTank);
+        if (!isMixed) {
+          _lengthIndicator.update(tags[field.key]);
         }
-        reveal(
-          ".edit-menu",
-          helpHtml("intro.buildings.circle_tank"),
-          { duration: 0, padding: 50 }
-        );
-      });
-      context.history().on("change.intro", function() {
-        wasChanged = true;
-        context.history().on("change.intro", null);
-        timeout2(function() {
-          if (context.history().undoAnnotation() === _t("operations.circularize.annotation.feature", { n: 1 })) {
-            continueTo(play);
+      }
+      const refreshStyles = () => {
+        _input.data([tagValue(utilGetSetValue(_input))]).classed("raw-value", isRawValue).classed("known-value", isKnownValue);
+      };
+      _input.on("input.refreshStyles", refreshStyles);
+      _combobox.on("update.refreshStyles", refreshStyles);
+      refreshStyles();
+    };
+    function registerDragAndDrop(selection2) {
+      var dragOrigin, targetIndex;
+      selection2.call(
+        drag_default().on("start", function(d3_event) {
+          dragOrigin = {
+            x: d3_event.x,
+            y: d3_event.y
+          };
+          targetIndex = null;
+        }).on("drag", function(d3_event) {
+          var x2 = d3_event.x - dragOrigin.x, y2 = d3_event.y - dragOrigin.y;
+          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
+          Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2)) <= 5) return;
+          var index = selection2.nodes().indexOf(this);
+          select_default2(this).classed("dragging", true);
+          targetIndex = null;
+          var targetIndexOffsetTop = null;
+          var draggedTagWidth = select_default2(this).node().offsetWidth;
+          if (field.key === "destination" || field.key === "via") {
+            _container.selectAll(".chip").style("transform", function(d2, index2) {
+              var node = select_default2(this).node();
+              if (index === index2) {
+                return "translate(" + x2 + "px, " + y2 + "px)";
+              } else if (index2 > index && d3_event.y > node.offsetTop) {
+                if (targetIndex === null || index2 > targetIndex) {
+                  targetIndex = index2;
+                }
+                return "translateY(-100%)";
+              } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
+                if (targetIndex === null || index2 < targetIndex) {
+                  targetIndex = index2;
+                }
+                return "translateY(100%)";
+              }
+              return null;
+            });
           } else {
-            continueTo(retryClickCircle);
+            _container.selectAll(".chip").each(function(d2, index2) {
+              var node = select_default2(this).node();
+              if (index !== index2 && d3_event.x < node.offsetLeft + node.offsetWidth + 5 && d3_event.x > node.offsetLeft && d3_event.y < node.offsetTop + node.offsetHeight && d3_event.y > node.offsetTop) {
+                targetIndex = index2;
+                targetIndexOffsetTop = node.offsetTop;
+              }
+            }).style("transform", function(d2, index2) {
+              var node = select_default2(this).node();
+              if (index === index2) {
+                return "translate(" + x2 + "px, " + y2 + "px)";
+              }
+              if (node.offsetTop === targetIndexOffsetTop) {
+                if (index2 < index && index2 >= targetIndex) {
+                  return "translateX(" + draggedTagWidth + "px)";
+                } else if (index2 > index && index2 <= targetIndex) {
+                  return "translateX(-" + draggedTagWidth + "px)";
+                }
+              }
+              return null;
+            });
           }
-        }, 500);
-      });
-      function continueTo(nextStep) {
-        context.on("enter.intro", null);
-        context.map().on("move.intro", null);
-        context.history().on("change.intro", null);
-        nextStep();
+        }).on("end", function() {
+          if (!select_default2(this).classed("dragging")) {
+            return;
+          }
+          var index = selection2.nodes().indexOf(this);
+          select_default2(this).classed("dragging", false);
+          _container.selectAll(".chip").style("transform", null);
+          if (typeof targetIndex === "number") {
+            var element = _multiData[index];
+            _multiData.splice(index, 1);
+            _multiData.splice(targetIndex, 0, element);
+            var t2 = {};
+            if (_multiData.length) {
+              t2[field.key] = _multiData.map(function(element2) {
+                return element2.key;
+              }).join(";");
+            } else {
+              t2[field.key] = void 0;
+            }
+            dispatch14.call("change", this, t2);
+          }
+          dragOrigin = void 0;
+          targetIndex = void 0;
+        })
+      );
+    }
+    combo.focus = function() {
+      _input.node().focus();
+    };
+    combo.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return combo;
+    };
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    return utilRebind(combo, dispatch14, "on");
+  }
+
+  // modules/ui/account.js
+  function uiAccount(context) {
+    const osm = context.connection();
+    function updateUserDetails(selection2) {
+      if (!osm) return;
+      if (!osm.authenticated()) {
+        render(selection2, null);
+      } else {
+        osm.userDetails((err, user) => render(selection2, user));
       }
     }
-    function retryClickCircle() {
-      context.enter(modeBrowse(context));
-      revealTank(tank, helpHtml("intro.buildings.retry_circle"), {
-        buttonText: _t.html("intro.ok"),
-        buttonCallback: function() {
-          continueTo(rightClickTank);
+    function render(selection2, user) {
+      let userInfo = selection2.select(".userInfo");
+      let loginLogout = selection2.select(".loginLogout");
+      if (user) {
+        userInfo.html("").classed("hide", false);
+        let userLink = userInfo.append("a").attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
+        if (user.image_url) {
+          userLink.append("img").attr("class", "icon pre-text user-icon").attr("src", user.image_url);
+        } else {
+          userLink.call(svgIcon("#iD-icon-avatar", "pre-text light"));
         }
-      });
-      function continueTo(nextStep) {
-        nextStep();
+        userLink.append("span").attr("class", "label").text(user.display_name);
+        loginLogout.classed("hide", false).select("a").text(_t("logout")).on("click", (e3) => {
+          e3.preventDefault();
+          osm.logout();
+          tryLogout();
+        });
+      } else {
+        userInfo.html("").classed("hide", true);
+        loginLogout.classed("hide", false).select("a").text(_t("login")).on("click", (e3) => {
+          e3.preventDefault();
+          osm.authenticate();
+        });
       }
     }
-    function play() {
-      dispatch10.call("done");
-      reveal(
-        ".ideditor",
-        helpHtml("intro.buildings.play", { next: _t("intro.startediting.title") }),
-        {
-          tooltipBox: ".intro-nav-wrap .chapter-startEditing",
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            reveal(".ideditor");
-          }
-        }
-      );
+    function tryLogout() {
+      if (!osm) return;
+      const url = osm.getUrlRoot() + "/logout?referer=%2Flogin";
+      const w2 = 600;
+      const h2 = 550;
+      const settings = [
+        ["width", w2],
+        ["height", h2],
+        ["left", window.screen.width / 2 - w2 / 2],
+        ["top", window.screen.height / 2 - h2 / 2]
+      ].map((x2) => x2.join("=")).join(",");
+      window.open(url, "_blank", settings);
     }
-    chapter.enter = function() {
-      addHouse();
-    };
-    chapter.exit = function() {
-      timeouts.forEach(window.clearTimeout);
-      context.on("enter.intro exit.intro", null);
-      context.map().on("move.intro drawn.intro", null);
-      context.history().on("change.intro", null);
-      context.container().select(".inspector-wrap").on("wheel.intro", null);
-      context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
-      context.container().select(".more-fields .combobox-input").on("click.intro", null);
-    };
-    chapter.restart = function() {
-      chapter.exit();
-      chapter.enter();
+    return function(selection2) {
+      if (!osm) return;
+      selection2.append("li").attr("class", "userInfo").classed("hide", true);
+      selection2.append("li").attr("class", "loginLogout").classed("hide", true).append("a").attr("href", "#");
+      osm.on("change.account", () => updateUserDetails(selection2));
+      updateUserDetails(selection2);
     };
-    return utilRebind(chapter, dispatch10, "on");
   }
 
-  // modules/ui/intro/start_editing.js
-  function uiIntroStartEditing(context, reveal) {
-    var dispatch10 = dispatch_default("done", "startEditing");
-    var modalSelection = select_default2(null);
-    var chapter = {
-      title: "intro.startediting.title"
-    };
-    function showHelp() {
-      reveal(
-        ".map-control.help-control",
-        helpHtml("intro.startediting.help"),
-        {
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            shortcuts();
-          }
+  // modules/ui/attribution.js
+  function uiAttribution(context) {
+    let _selection = select_default2(null);
+    function render(selection2, data, klass) {
+      let div = selection2.selectAll(".".concat(klass)).data([0]);
+      div = div.enter().append("div").attr("class", klass).merge(div);
+      let attributions = div.selectAll(".attribution").data(data, (d2) => d2.id);
+      attributions.exit().remove();
+      attributions = attributions.enter().append("span").attr("class", "attribution").each((d2, i3, nodes) => {
+        let attribution = select_default2(nodes[i3]);
+        if (d2.terms_html) {
+          attribution.html(d2.terms_html);
+          return;
         }
-      );
-    }
-    function shortcuts() {
-      reveal(
-        ".map-control.help-control",
-        helpHtml("intro.startediting.shortcuts"),
-        {
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            showSave();
-          }
+        if (d2.terms_url) {
+          attribution = attribution.append("a").attr("href", d2.terms_url).attr("target", "_blank");
         }
-      );
-    }
-    function showSave() {
-      context.container().selectAll(".shaded").remove();
-      reveal(
-        ".top-toolbar button.save",
-        helpHtml("intro.startediting.save"),
-        {
-          buttonText: _t.html("intro.ok"),
-          buttonCallback: function() {
-            showStart();
-          }
+        const sourceID = d2.id.replace(/\./g, "<TX_DOT>");
+        const terms_text = _t(
+          "imagery.".concat(sourceID, ".attribution.text"),
+          { default: d2.terms_text || d2.id || d2.name() }
+        );
+        if (d2.icon && !d2.overlay) {
+          attribution.append("img").attr("class", "source-image").attr("src", d2.icon);
         }
-      );
-    }
-    function showStart() {
-      context.container().selectAll(".shaded").remove();
-      modalSelection = uiModal(context.container());
-      modalSelection.select(".modal").attr("class", "modal-splash modal");
-      modalSelection.selectAll(".close").remove();
-      var startbutton = modalSelection.select(".content").attr("class", "fillL").append("button").attr("class", "modal-section huge-modal-button").on("click", function() {
-        modalSelection.remove();
+        attribution.append("span").attr("class", "attribution-text").text(terms_text);
+      }).merge(attributions);
+      let copyright = attributions.selectAll(".copyright-notice").data((d2) => {
+        let notice = d2.copyrightNotices(context.map().zoom(), context.map().extent());
+        return notice ? [notice] : [];
       });
-      startbutton.append("svg").attr("class", "illustration").append("use").attr("xlink:href", "#iD-logo-walkthrough");
-      startbutton.append("h2").call(_t.append("intro.startediting.start"));
-      dispatch10.call("startEditing");
+      copyright.exit().remove();
+      copyright = copyright.enter().append("span").attr("class", "copyright-notice").merge(copyright);
+      copyright.text(String);
     }
-    chapter.enter = function() {
-      showHelp();
-    };
-    chapter.exit = function() {
-      modalSelection.remove();
-      context.container().selectAll(".shaded").remove();
+    function update() {
+      let baselayer = context.background().baseLayerSource();
+      _selection.call(render, baselayer ? [baselayer] : [], "base-layer-attribution");
+      const z2 = context.map().zoom();
+      let overlays = context.background().overlayLayerSources() || [];
+      _selection.call(render, overlays.filter((s2) => s2.validZoom(z2)), "overlay-layer-attribution");
+    }
+    return function(selection2) {
+      _selection = selection2;
+      context.background().on("change.attribution", update);
+      context.map().on("move.attribution", throttle_default(update, 400, { leading: false }));
+      update();
     };
-    return utilRebind(chapter, dispatch10, "on");
   }
 
-  // modules/ui/intro/intro.js
-  var chapterUi = {
-    welcome: uiIntroWelcome,
-    navigation: uiIntroNavigation,
-    point: uiIntroPoint,
-    area: uiIntroArea,
-    line: uiIntroLine,
-    building: uiIntroBuilding,
-    startEditing: uiIntroStartEditing
-  };
-  var chapterFlow = [
-    "welcome",
-    "navigation",
-    "point",
-    "area",
-    "line",
-    "building",
-    "startEditing"
-  ];
-  function uiIntro(context) {
-    const INTRO_IMAGERY = "EsriWorldImageryClarity";
-    let _introGraph = {};
-    let _currChapter;
-    function intro(selection2) {
-      _mainFileFetcher.get("intro_graph").then((dataIntroGraph) => {
-        for (let id2 in dataIntroGraph) {
-          if (!_introGraph[id2]) {
-            _introGraph[id2] = osmEntity(localize(dataIntroGraph[id2]));
-          }
-        }
-        selection2.call(startIntro);
-      }).catch(function() {
+  // modules/ui/contributors.js
+  function uiContributors(context) {
+    var osm = context.connection(), debouncedUpdate = debounce_default(function() {
+      update();
+    }, 1e3), limit = 4, hidden = false, wrap2 = select_default2(null);
+    function update() {
+      if (!osm) return;
+      var users = {}, entities = context.history().intersects(context.map().extent());
+      entities.forEach(function(entity) {
+        if (entity && entity.user) users[entity.user] = true;
       });
-    }
-    function startIntro(selection2) {
-      context.enter(modeBrowse(context));
-      let osm = context.connection();
-      let history = context.history().toJSON();
-      let hash = window.location.hash;
-      let center = context.map().center();
-      let zoom = context.map().zoom();
-      let background = context.background().baseLayerSource();
-      let overlays = context.background().overlayLayerSources();
-      let opacity = context.container().selectAll(".main-map .layer-background").style("opacity");
-      let caches = osm && osm.caches();
-      let baseEntities = context.history().graph().base().entities;
-      context.ui().sidebar.expand();
-      context.container().selectAll("button.sidebar-toggle").classed("disabled", true);
-      context.inIntro(true);
-      if (osm) {
-        osm.toggle(false).reset();
+      var u2 = Object.keys(users), subset = u2.slice(0, u2.length > limit ? limit - 1 : limit);
+      wrap2.html("").call(svgIcon("#iD-icon-nearby", "pre-text light"));
+      var userList = select_default2(document.createElement("span"));
+      userList.selectAll().data(subset).enter().append("a").attr("class", "user-link").attr("href", function(d2) {
+        return osm.userURL(d2);
+      }).attr("target", "_blank").text(String);
+      if (u2.length > limit) {
+        var count = select_default2(document.createElement("span"));
+        var othersNum = u2.length - limit + 1;
+        count.append("a").attr("target", "_blank").attr("href", function() {
+          return osm.changesetsURL(context.map().center(), context.map().zoom());
+        }).text(othersNum);
+        wrap2.append("span").html(_t.html("contributors.truncated_list", { n: othersNum, users: { html: userList.html() }, count: { html: count.html() } }));
+      } else {
+        wrap2.append("span").html(_t.html("contributors.list", { users: { html: userList.html() } }));
       }
-      context.history().reset();
-      context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
-      context.history().checkpoint("initial");
-      let imagery = context.background().findSource(INTRO_IMAGERY);
-      if (imagery) {
-        context.background().baseLayerSource(imagery);
+      if (!u2.length) {
+        hidden = true;
+        wrap2.transition().style("opacity", 0);
+      } else if (hidden) {
+        wrap2.transition().style("opacity", 1);
+      }
+    }
+    return function(selection2) {
+      if (!osm) return;
+      wrap2 = selection2;
+      update();
+      osm.on("loaded.contributors", debouncedUpdate);
+      context.map().on("move.contributors", debouncedUpdate);
+    };
+  }
+
+  // modules/ui/edit_menu.js
+  function uiEditMenu(context) {
+    var dispatch14 = dispatch_default("toggled");
+    var _menu = select_default2(null);
+    var _operations = [];
+    var _anchorLoc = [0, 0];
+    var _anchorLocLonLat = [0, 0];
+    var _triggerType = "";
+    var _vpTopMargin = 85;
+    var _vpBottomMargin = 45;
+    var _vpSideMargin = 35;
+    var _menuTop = false;
+    var _menuHeight;
+    var _menuWidth;
+    var _verticalPadding = 4;
+    var _tooltipWidth = 210;
+    var _menuSideMargin = 10;
+    var _tooltips = [];
+    var editMenu = function(selection2) {
+      var isTouchMenu = _triggerType.includes("touch") || _triggerType.includes("pen");
+      var ops = _operations.filter(function(op) {
+        return !isTouchMenu || !op.mouseOnly;
+      });
+      if (!ops.length) return;
+      _tooltips = [];
+      _menuTop = isTouchMenu;
+      var showLabels = isTouchMenu;
+      var buttonHeight = showLabels ? 32 : 34;
+      if (showLabels) {
+        _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function(op) {
+          return op.title.length;
+        })));
       } else {
-        context.background().bing();
+        _menuWidth = 44;
       }
-      overlays.forEach((d) => context.background().toggleOverlayLayer(d));
-      let layers = context.layers();
-      layers.all().forEach((item) => {
-        if (typeof item.layer.enabled === "function") {
-          item.layer.enabled(item.id === "osm");
-        }
+      _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
+      _menu = selection2.append("div").attr("class", "edit-menu").classed("touch-menu", isTouchMenu).style("padding", _verticalPadding + "px 0");
+      var buttons = _menu.selectAll(".edit-menu-item").data(ops);
+      var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
+        return "edit-menu-item edit-menu-item-" + d2.id;
+      }).style("height", buttonHeight + "px").on("click", click).on("pointerup", pointerup).on("pointerdown mousedown", function pointerdown(d3_event) {
+        d3_event.stopPropagation();
+      }).on("mouseenter.highlight", function(d3_event, d2) {
+        if (!d2.relatedEntityIds || select_default2(this).classed("disabled")) return;
+        utilHighlightEntities(d2.relatedEntityIds(), true, context);
+      }).on("mouseleave.highlight", function(d3_event, d2) {
+        if (!d2.relatedEntityIds) return;
+        utilHighlightEntities(d2.relatedEntityIds(), false, context);
+      });
+      buttonsEnter.each(function(d2) {
+        var tooltip = uiTooltip().heading(() => d2.title).title(d2.tooltip).keys([d2.keys[0]]);
+        _tooltips.push(tooltip);
+        select_default2(this).call(tooltip).append("div").attr("class", "icon-wrap").call(svgIcon(d2.icon && d2.icon() || "#iD-operation-" + d2.id, "operation"));
       });
-      context.container().selectAll(".main-map .layer-background").style("opacity", 1);
-      let curtain = uiCurtain(context.container().node());
-      selection2.call(curtain);
-      corePreferences("walkthrough_started", "yes");
-      let storedProgress = corePreferences("walkthrough_progress") || "";
-      let progress = storedProgress.split(";").filter(Boolean);
-      let chapters = chapterFlow.map((chapter, i2) => {
-        let s = chapterUi[chapter](context, curtain.reveal).on("done", () => {
-          buttons.filter((d) => d.title === s.title).classed("finished", true);
-          if (i2 < chapterFlow.length - 1) {
-            const next = chapterFlow[i2 + 1];
-            context.container().select(`button.chapter-${next}`).classed("next", true);
-          }
-          progress.push(chapter);
-          corePreferences("walkthrough_progress", utilArrayUniq(progress).join(";"));
+      if (showLabels) {
+        buttonsEnter.append("span").attr("class", "label").each(function(d2) {
+          select_default2(this).call(d2.title);
         });
-        return s;
+      }
+      buttonsEnter.merge(buttons).classed("disabled", function(d2) {
+        return d2.disabled();
       });
-      chapters[chapters.length - 1].on("startEditing", () => {
-        progress.push("startEditing");
-        corePreferences("walkthrough_progress", utilArrayUniq(progress).join(";"));
-        let incomplete = utilArrayDifference(chapterFlow, progress);
-        if (!incomplete.length) {
-          corePreferences("walkthrough_completed", "yes");
+      updatePosition();
+      var initialScale = context.projection.scale();
+      context.map().on("move.edit-menu", function() {
+        if (initialScale !== context.projection.scale()) {
+          editMenu.close();
         }
-        curtain.remove();
-        navwrap.remove();
-        context.container().selectAll(".main-map .layer-background").style("opacity", opacity);
-        context.container().selectAll("button.sidebar-toggle").classed("disabled", false);
-        if (osm) {
-          osm.toggle(true).reset().caches(caches);
+      }).on("drawn.edit-menu", function(info) {
+        if (info.full) updatePosition();
+      });
+      var lastPointerUpType;
+      function pointerup(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
+      }
+      function click(d3_event, operation2) {
+        d3_event.stopPropagation();
+        if (operation2.relatedEntityIds) {
+          utilHighlightEntities(operation2.relatedEntityIds(), false, context);
         }
-        context.history().reset().merge(Object.values(baseEntities));
-        context.background().baseLayerSource(background);
-        overlays.forEach((d) => context.background().toggleOverlayLayer(d));
-        if (history) {
-          context.history().fromJSON(history, false);
-        }
-        context.map().centerZoom(center, zoom);
-        window.location.replace(hash);
-        context.inIntro(false);
-      });
-      let navwrap = selection2.append("div").attr("class", "intro-nav-wrap fillD");
-      navwrap.append("svg").attr("class", "intro-nav-wrap-logo").append("use").attr("xlink:href", "#iD-logo-walkthrough");
-      let buttonwrap = navwrap.append("div").attr("class", "joined").selectAll("button.chapter");
-      let buttons = buttonwrap.data(chapters).enter().append("button").attr("class", (d, i2) => `chapter chapter-${chapterFlow[i2]}`).on("click", enterChapter);
-      buttons.append("span").html((d) => _t.html(d.title));
-      buttons.append("span").attr("class", "status").call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward", "inline"));
-      enterChapter(null, chapters[0]);
-      function enterChapter(d3_event, newChapter) {
-        if (_currChapter) {
-          _currChapter.exit();
-        }
-        context.enter(modeBrowse(context));
-        _currChapter = newChapter;
-        _currChapter.enter();
-        buttons.classed("next", false).classed("active", (d) => d.title === _currChapter.title);
-      }
-    }
-    return intro;
-  }
-
-  // modules/ui/issues_info.js
-  function uiIssuesInfo(context) {
-    var warningsItem = {
-      id: "warnings",
-      count: 0,
-      iconID: "iD-icon-alert",
-      descriptionID: "issues.warnings_and_errors"
-    };
-    var resolvedItem = {
-      id: "resolved",
-      count: 0,
-      iconID: "iD-icon-apply",
-      descriptionID: "issues.user_resolved_issues"
-    };
-    function update(selection2) {
-      var shownItems = [];
-      var liveIssues = context.validator().getIssues({
-        what: corePreferences("validate-what") || "edited",
-        where: corePreferences("validate-where") || "all"
-      });
-      if (liveIssues.length) {
-        warningsItem.count = liveIssues.length;
-        shownItems.push(warningsItem);
-      }
-      if (corePreferences("validate-what") === "all") {
-        var resolvedIssues = context.validator().getResolvedIssues();
-        if (resolvedIssues.length) {
-          resolvedItem.count = resolvedIssues.length;
-          shownItems.push(resolvedItem);
+        if (operation2.disabled()) {
+          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
+            context.ui().flash.duration(4e3).iconName("#iD-operation-" + operation2.id).iconClass("operation disabled").label(operation2.tooltip())();
+          }
+        } else {
+          if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
+            context.ui().flash.duration(2e3).iconName("#iD-operation-" + operation2.id).iconClass("operation").label(operation2.annotation() || operation2.title)();
+          }
+          operation2();
+          editMenu.close();
         }
+        lastPointerUpType = null;
       }
-      var chips = selection2.selectAll(".chip").data(shownItems, function(d) {
-        return d.id;
-      });
-      chips.exit().remove();
-      var enter = chips.enter().append("a").attr("class", function(d) {
-        return "chip " + d.id + "-count";
-      }).attr("href", "#").each(function(d) {
-        var chipSelection = select_default2(this);
-        var tooltipBehavior = uiTooltip().placement("top").title(() => _t.append(d.descriptionID));
-        chipSelection.call(tooltipBehavior).on("click", function(d3_event) {
-          d3_event.preventDefault();
-          tooltipBehavior.hide(select_default2(this));
-          context.ui().togglePanes(context.container().select(".map-panes .issues-pane"));
-        });
-        chipSelection.call(svgIcon("#" + d.iconID));
-      });
-      enter.append("span").attr("class", "count");
-      enter.merge(chips).selectAll("span.count").text(function(d) {
-        return d.count.toString();
-      });
-    }
-    return function(selection2) {
-      update(selection2);
-      context.validator().on("validated.infobox", function() {
-        update(selection2);
-      });
+      dispatch14.call("toggled", this, true);
     };
-  }
-
-  // modules/ui/map_in_map.js
-  function uiMapInMap(context) {
-    function mapInMap(selection2) {
-      var backgroundLayer = rendererTileLayer(context);
-      var overlayLayers = {};
-      var projection2 = geoRawMercator();
-      var dataLayer = svgData(projection2, context).showLabels(false);
-      var debugLayer = svgDebug(projection2, context);
-      var zoom = zoom_default2().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on("start", zoomStarted).on("zoom", zoomed).on("end", zoomEnded);
-      var wrap2 = select_default2(null);
-      var tiles = select_default2(null);
-      var viewport = select_default2(null);
-      var _isTransformed = false;
-      var _isHidden = true;
-      var _skipEvents = false;
-      var _gesture = null;
-      var _zDiff = 6;
-      var _dMini;
-      var _cMini;
-      var _tStart;
-      var _tCurr;
-      var _timeoutID;
-      function zoomStarted() {
-        if (_skipEvents)
-          return;
-        _tStart = _tCurr = projection2.transform();
-        _gesture = null;
+    function updatePosition() {
+      if (!_menu || _menu.empty()) return;
+      var anchorLoc = context.projection(_anchorLocLonLat);
+      var viewport = context.surfaceRect();
+      if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
+        editMenu.close();
+        return;
       }
-      function zoomed(d3_event) {
-        if (_skipEvents)
-          return;
-        var x = d3_event.transform.x;
-        var y = d3_event.transform.y;
-        var k = d3_event.transform.k;
-        var isZooming = k !== _tStart.k;
-        var isPanning = x !== _tStart.x || y !== _tStart.y;
-        if (!isZooming && !isPanning) {
-          return;
-        }
-        if (!_gesture) {
-          _gesture = isZooming ? "zoom" : "pan";
-        }
-        var tMini = projection2.transform();
-        var tX, tY, scale;
-        if (_gesture === "zoom") {
-          scale = k / tMini.k;
-          tX = (_cMini[0] / scale - _cMini[0]) * scale;
-          tY = (_cMini[1] / scale - _cMini[1]) * scale;
+      var menuLeft = displayOnLeft(viewport);
+      var offset = [0, 0];
+      offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
+      if (_menuTop) {
+        if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
+          offset[1] = -anchorLoc[1] + _vpTopMargin;
         } else {
-          k = tMini.k;
-          scale = 1;
-          tX = x - tMini.x;
-          tY = y - tMini.y;
+          offset[1] = -_menuHeight;
         }
-        utilSetTransform(tiles, tX, tY, scale);
-        utilSetTransform(viewport, 0, 0, scale);
-        _isTransformed = true;
-        _tCurr = identity2.translate(x, y).scale(k);
-        var zMain = geoScaleToZoom(context.projection.scale());
-        var zMini = geoScaleToZoom(k);
-        _zDiff = zMain - zMini;
-        queueRedraw();
-      }
-      function zoomEnded() {
-        if (_skipEvents)
-          return;
-        if (_gesture !== "pan")
-          return;
-        updateProjection();
-        _gesture = null;
-        context.map().center(projection2.invert(_cMini));
-      }
-      function updateProjection() {
-        var loc = context.map().center();
-        var tMain = context.projection.transform();
-        var zMain = geoScaleToZoom(tMain.k);
-        var zMini = Math.max(zMain - _zDiff, 0.5);
-        var kMini = geoZoomToScale(zMini);
-        projection2.translate([tMain.x, tMain.y]).scale(kMini);
-        var point = projection2(loc);
-        var mouse = _gesture === "pan" ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
-        var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
-        var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
-        projection2.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
-        _tCurr = projection2.transform();
-        if (_isTransformed) {
-          utilSetTransform(tiles, 0, 0);
-          utilSetTransform(viewport, 0, 0);
-          _isTransformed = false;
+      } else {
+        if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
+          offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
+        } else {
+          offset[1] = 0;
         }
-        zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
-        _skipEvents = true;
-        wrap2.call(zoom.transform, _tCurr);
-        _skipEvents = false;
       }
-      function redraw() {
-        clearTimeout(_timeoutID);
-        if (_isHidden)
-          return;
-        updateProjection();
-        var zMini = geoScaleToZoom(projection2.scale());
-        tiles = wrap2.selectAll(".map-in-map-tiles").data([0]);
-        tiles = tiles.enter().append("div").attr("class", "map-in-map-tiles").merge(tiles);
-        backgroundLayer.source(context.background().baseLayerSource()).projection(projection2).dimensions(_dMini);
-        var background = tiles.selectAll(".map-in-map-background").data([0]);
-        background.enter().append("div").attr("class", "map-in-map-background").merge(background).call(backgroundLayer);
-        var overlaySources = context.background().overlayLayerSources();
-        var activeOverlayLayers = [];
-        for (var i2 = 0; i2 < overlaySources.length; i2++) {
-          if (overlaySources[i2].validZoom(zMini)) {
-            if (!overlayLayers[i2])
-              overlayLayers[i2] = rendererTileLayer(context);
-            activeOverlayLayers.push(overlayLayers[i2].source(overlaySources[i2]).projection(projection2).dimensions(_dMini));
+      var origin = geoVecAdd(anchorLoc, offset);
+      _menu.style("left", origin[0] + "px").style("top", origin[1] + "px");
+      var tooltipSide = tooltipPosition(viewport, menuLeft);
+      _tooltips.forEach(function(tooltip) {
+        tooltip.placement(tooltipSide);
+      });
+      function displayOnLeft(viewport2) {
+        if (_mainLocalizer.textDirection() === "ltr") {
+          if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport2.width - _vpSideMargin) {
+            return true;
           }
+          return false;
+        } else {
+          if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
+            return false;
+          }
+          return true;
         }
-        var overlay = tiles.selectAll(".map-in-map-overlay").data([0]);
-        overlay = overlay.enter().append("div").attr("class", "map-in-map-overlay").merge(overlay);
-        var overlays = overlay.selectAll("div").data(activeOverlayLayers, function(d) {
-          return d.source().name();
-        });
-        overlays.exit().remove();
-        overlays = overlays.enter().append("div").merge(overlays).each(function(layer) {
-          select_default2(this).call(layer);
-        });
-        var dataLayers = tiles.selectAll(".map-in-map-data").data([0]);
-        dataLayers.exit().remove();
-        dataLayers = dataLayers.enter().append("svg").attr("class", "map-in-map-data").merge(dataLayers).call(dataLayer).call(debugLayer);
-        if (_gesture !== "pan") {
-          var getPath = path_default(projection2);
-          var bbox = { 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]);
-          path.enter().append("path").attr("class", "map-in-map-bbox").merge(path).attr("d", getPath).classed("thick", function(d) {
-            return getPath.area(d) < 30;
-          });
-        }
-      }
-      function queueRedraw() {
-        clearTimeout(_timeoutID);
-        _timeoutID = setTimeout(function() {
-          redraw();
-        }, 750);
       }
-      function toggle(d3_event) {
-        if (d3_event)
-          d3_event.preventDefault();
-        _isHidden = !_isHidden;
-        context.container().select(".minimap-toggle-item").classed("active", !_isHidden).select("input").property("checked", !_isHidden);
-        if (_isHidden) {
-          wrap2.style("display", "block").style("opacity", "1").transition().duration(200).style("opacity", "0").on("end", function() {
-            selection2.selectAll(".map-in-map").style("display", "none");
-          });
+      function tooltipPosition(viewport2, menuLeft2) {
+        if (_mainLocalizer.textDirection() === "ltr") {
+          if (menuLeft2) {
+            return "left";
+          }
+          if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport2.width - _vpSideMargin) {
+            return "left";
+          }
+          return "right";
         } else {
-          wrap2.style("display", "block").style("opacity", "0").transition().duration(200).style("opacity", "1").on("end", function() {
-            redraw();
-          });
+          if (!menuLeft2) {
+            return "right";
+          }
+          if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
+            return "right";
+          }
+          return "left";
         }
       }
-      uiMapInMap.toggle = toggle;
-      wrap2 = selection2.selectAll(".map-in-map").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "map-in-map").style("display", _isHidden ? "none" : "block").call(zoom).on("dblclick.zoom", null).merge(wrap2);
-      _dMini = [200, 150];
-      _cMini = geoVecScale(_dMini, 0.5);
-      context.map().on("drawn.map-in-map", function(drawn) {
-        if (drawn.full === true) {
-          redraw();
-        }
-      });
-      redraw();
-      context.keybinding().on(_t("background.minimap.key"), toggle);
     }
-    return mapInMap;
-  }
-
-  // modules/ui/notice.js
-  function uiNotice(context) {
-    return function(selection2) {
-      var div = selection2.append("div").attr("class", "notice");
-      var button = div.append("button").attr("class", "zoom-to notice fillD").on("click", function() {
-        context.map().zoomEase(context.minEditableZoom());
-      }).on("wheel", function(d3_event) {
-        var e22 = new WheelEvent(d3_event.type, d3_event);
-        context.surface().node().dispatchEvent(e22);
-      });
-      button.call(svgIcon("#iD-icon-plus", "pre-text")).append("span").attr("class", "label").call(_t.append("zoom_in_edit"));
-      function disableTooHigh() {
-        var canEdit = context.map().zoom() >= context.minEditableZoom();
-        div.style("display", canEdit ? "none" : "block");
-      }
-      context.map().on("move.notice", debounce_default(disableTooHigh, 500));
-      disableTooHigh();
+    editMenu.close = function() {
+      context.map().on("move.edit-menu", null).on("drawn.edit-menu", null);
+      _menu.remove();
+      _tooltips = [];
+      dispatch14.call("toggled", this, false);
+    };
+    editMenu.anchorLoc = function(val) {
+      if (!arguments.length) return _anchorLoc;
+      _anchorLoc = val;
+      _anchorLocLonLat = context.projection.invert(_anchorLoc);
+      return editMenu;
+    };
+    editMenu.triggerType = function(val) {
+      if (!arguments.length) return _triggerType;
+      _triggerType = val;
+      return editMenu;
+    };
+    editMenu.operations = function(val) {
+      if (!arguments.length) return _operations;
+      _operations = val;
+      return editMenu;
     };
+    return utilRebind(editMenu, dispatch14, "on");
   }
 
-  // modules/ui/photoviewer.js
-  function uiPhotoviewer(context) {
-    var dispatch10 = dispatch_default("resize");
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function photoviewer(selection2) {
-      selection2.append("button").attr("class", "thumb-hide").attr("title", _t("icons.close")).on("click", function() {
-        if (services.streetside) {
-          services.streetside.hideViewer(context);
-        }
-        if (services.mapillary) {
-          services.mapillary.hideViewer(context);
-        }
-        if (services.kartaview) {
-          services.kartaview.hideViewer(context);
-        }
-      }).append("div").call(svgIcon("#iD-icon-close"));
-      function preventDefault(d3_event) {
-        d3_event.preventDefault();
-      }
-      selection2.append("button").attr("class", "resize-handle-xy").on("touchstart touchdown touchend", preventDefault).on(
-        _pointerPrefix + "down",
-        buildResizeListener(selection2, "resize", dispatch10, { resizeOnX: true, resizeOnY: true })
-      );
-      selection2.append("button").attr("class", "resize-handle-x").on("touchstart touchdown touchend", preventDefault).on(
-        _pointerPrefix + "down",
-        buildResizeListener(selection2, "resize", dispatch10, { resizeOnX: true })
-      );
-      selection2.append("button").attr("class", "resize-handle-y").on("touchstart touchdown touchend", preventDefault).on(
-        _pointerPrefix + "down",
-        buildResizeListener(selection2, "resize", dispatch10, { resizeOnY: true })
-      );
-      function buildResizeListener(target, eventName, dispatch11, options2) {
-        var resizeOnX = !!options2.resizeOnX;
-        var resizeOnY = !!options2.resizeOnY;
-        var minHeight = options2.minHeight || 240;
-        var minWidth = options2.minWidth || 320;
-        var pointerId;
-        var startX;
-        var startY;
-        var startWidth;
-        var startHeight;
-        function startResize(d3_event) {
-          if (pointerId !== (d3_event.pointerId || "mouse"))
-            return;
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          var mapSize = context.map().dimensions();
-          if (resizeOnX) {
-            var maxWidth = mapSize[0];
-            var newWidth = clamp3(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
-            target.style("width", newWidth + "px");
-          }
-          if (resizeOnY) {
-            var maxHeight = mapSize[1] - 90;
-            var newHeight = clamp3(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
-            target.style("height", newHeight + "px");
-          }
-          dispatch11.call(eventName, target, utilGetDimensions(target, true));
-        }
-        function clamp3(num, min3, max3) {
-          return Math.max(min3, Math.min(num, max3));
-        }
-        function stopResize(d3_event) {
-          if (pointerId !== (d3_event.pointerId || "mouse"))
-            return;
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          select_default2(window).on("." + eventName, null);
+  // modules/ui/feature_info.js
+  function uiFeatureInfo(context) {
+    function update(selection2) {
+      var features = context.features();
+      var stats = features.stats();
+      var count = 0;
+      var hiddenList = features.hidden().map(function(k2) {
+        if (stats[k2]) {
+          count += stats[k2];
+          return _t.append("inspector.title_count", {
+            title: _t("feature." + k2 + ".description"),
+            count: stats[k2]
+          });
         }
-        return function initResize(d3_event) {
+        return null;
+      }).filter(Boolean);
+      selection2.text("");
+      if (hiddenList.length) {
+        var tooltipBehavior = uiTooltip().placement("top").title(function() {
+          return (selection3) => {
+            hiddenList.forEach((hiddenFeature) => {
+              selection3.append("div").call(hiddenFeature);
+            });
+          };
+        });
+        selection2.append("a").attr("class", "chip").attr("href", "#").call(_t.append("feature_info.hidden_warning", { count })).call(tooltipBehavior).on("click", function(d3_event) {
+          tooltipBehavior.hide();
           d3_event.preventDefault();
-          d3_event.stopPropagation();
-          pointerId = d3_event.pointerId || "mouse";
-          startX = d3_event.clientX;
-          startY = d3_event.clientY;
-          var targetRect = target.node().getBoundingClientRect();
-          startWidth = targetRect.width;
-          startHeight = targetRect.height;
-          select_default2(window).on(_pointerPrefix + "move." + eventName, startResize, false).on(_pointerPrefix + "up." + eventName, stopResize, false);
-          if (_pointerPrefix === "pointer") {
-            select_default2(window).on("pointercancel." + eventName, stopResize, false);
-          }
-        };
+          context.ui().togglePanes(context.container().select(".map-panes .map-data-pane"));
+        });
       }
+      selection2.classed("hide", !hiddenList.length);
     }
-    photoviewer.onMapResize = function() {
-      var photoviewer2 = context.container().select(".photoviewer");
-      var content = context.container().select(".main-content");
-      var mapDimensions = utilGetDimensions(content, true);
-      var photoDimensions = utilGetDimensions(photoviewer2, true);
-      if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
-        var setPhotoDimensions = [
-          Math.min(photoDimensions[0], mapDimensions[0]),
-          Math.min(photoDimensions[1], mapDimensions[1] - 90)
-        ];
-        photoviewer2.style("width", setPhotoDimensions[0] + "px").style("height", setPhotoDimensions[1] + "px");
-        dispatch10.call("resize", photoviewer2, setPhotoDimensions);
-      }
-    };
-    return utilRebind(photoviewer, dispatch10, "on");
-  }
-
-  // modules/ui/restore.js
-  function uiRestore(context) {
     return function(selection2) {
-      if (!context.history().hasRestorableChanges())
-        return;
-      let modalSelection = uiModal(selection2, true);
-      modalSelection.select(".modal").attr("class", "modal fillL");
-      let introModal = modalSelection.select(".content");
-      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("restore.heading"));
-      introModal.append("div").attr("class", "modal-section").append("p").call(_t.append("restore.description"));
-      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
-      let restore = buttonWrap.append("button").attr("class", "restore").on("click", () => {
-        context.history().restore();
-        modalSelection.remove();
-      });
-      restore.append("svg").attr("class", "logo logo-restore").append("use").attr("xlink:href", "#iD-logo-restore");
-      restore.append("div").call(_t.append("restore.restore"));
-      let reset = buttonWrap.append("button").attr("class", "reset").on("click", () => {
-        context.history().clearSaved();
-        modalSelection.remove();
+      update(selection2);
+      context.features().on("change.feature_info", function() {
+        update(selection2);
       });
-      reset.append("svg").attr("class", "logo logo-reset").append("use").attr("xlink:href", "#iD-logo-reset");
-      reset.append("div").call(_t.append("restore.reset"));
-      restore.node().focus();
     };
   }
 
-  // modules/ui/scale.js
-  function uiScale(context) {
-    var projection2 = context.projection, isImperial = !_mainLocalizer.usesMetric(), maxLength = 180, tickHeight = 8;
-    function scaleDefs(loc1, loc2) {
-      var lat = (loc2[1] + loc1[1]) / 2, conversion = isImperial ? 3.28084 : 1, dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion, scale = { dist: 0, px: 0, text: "" }, buckets, i2, val, dLon;
-      if (isImperial) {
-        buckets = [528e4, 528e3, 52800, 5280, 500, 50, 5, 1];
-      } else {
-        buckets = [5e6, 5e5, 5e4, 5e3, 500, 50, 5, 1];
-      }
-      for (i2 = 0; i2 < buckets.length; i2++) {
-        val = buckets[i2];
-        if (dist >= val) {
-          scale.dist = Math.floor(dist / val) * val;
-          break;
-        } else {
-          scale.dist = +dist.toFixed(2);
-        }
+  // modules/ui/flash.js
+  function uiFlash(context) {
+    var _flashTimer;
+    var _duration = 2e3;
+    var _iconName = "#iD-icon-no";
+    var _iconClass = "disabled";
+    var _label = (s2) => s2.text("");
+    function flash() {
+      if (_flashTimer) {
+        _flashTimer.stop();
       }
-      dLon = geoMetersToLon(scale.dist / conversion, lat);
-      scale.px = Math.round(projection2([loc1[0] + dLon, loc1[1]])[0]);
-      scale.text = displayLength(scale.dist / conversion, isImperial);
-      return scale;
-    }
-    function update(selection2) {
-      var dims = context.map().dimensions(), loc1 = projection2.invert([0, dims[1]]), loc2 = projection2.invert([maxLength, dims[1]]), scale = scaleDefs(loc1, loc2);
-      selection2.select(".scale-path").attr("d", "M0.5,0.5v" + tickHeight + "h" + scale.px + "v-" + tickHeight);
-      selection2.select(".scale-text").style(_mainLocalizer.textDirection() === "ltr" ? "left" : "right", scale.px + 16 + "px").text(scale.text);
+      context.container().select(".main-footer-wrap").classed("footer-hide", true).classed("footer-show", false);
+      context.container().select(".flash-wrap").classed("footer-hide", false).classed("footer-show", true);
+      var content = context.container().select(".flash-wrap").selectAll(".flash-content").data([0]);
+      var contentEnter = content.enter().append("div").attr("class", "flash-content");
+      var iconEnter = contentEnter.append("svg").attr("class", "flash-icon icon").append("g").attr("transform", "translate(10,10)");
+      iconEnter.append("circle").attr("r", 9);
+      iconEnter.append("use").attr("transform", "translate(-7,-7)").attr("width", "14").attr("height", "14");
+      contentEnter.append("div").attr("class", "flash-text");
+      content = content.merge(contentEnter);
+      content.selectAll(".flash-icon").attr("class", "icon flash-icon " + (_iconClass || ""));
+      content.selectAll(".flash-icon use").attr("xlink:href", _iconName);
+      content.selectAll(".flash-text").attr("class", "flash-text").call(_label);
+      _flashTimer = timeout_default(function() {
+        _flashTimer = null;
+        context.container().select(".main-footer-wrap").classed("footer-hide", false).classed("footer-show", true);
+        context.container().select(".flash-wrap").classed("footer-hide", true).classed("footer-show", false);
+      }, _duration);
+      return content;
     }
-    return function(selection2) {
-      function switchUnits() {
-        isImperial = !isImperial;
-        selection2.call(update);
+    flash.duration = function(_2) {
+      if (!arguments.length) return _duration;
+      _duration = _2;
+      return flash;
+    };
+    flash.label = function(_2) {
+      if (!arguments.length) return _label;
+      if (typeof _2 !== "function") {
+        _label = (selection2) => selection2.text(_2);
+      } else {
+        _label = (selection2) => selection2.text("").call(_2);
       }
-      var scalegroup = selection2.append("svg").attr("class", "scale").on("click", switchUnits).append("g").attr("transform", "translate(10,11)");
-      scalegroup.append("path").attr("class", "scale-path");
-      selection2.append("div").attr("class", "scale-text");
-      selection2.call(update);
-      context.map().on("move.scale", function() {
-        update(selection2);
-      });
+      return flash;
+    };
+    flash.iconName = function(_2) {
+      if (!arguments.length) return _iconName;
+      _iconName = _2;
+      return flash;
+    };
+    flash.iconClass = function(_2) {
+      if (!arguments.length) return _iconClass;
+      _iconClass = _2;
+      return flash;
     };
+    return flash;
   }
 
-  // modules/ui/shortcuts.js
-  function uiShortcuts(context) {
-    var detected = utilDetect();
-    var _activeTab = 0;
-    var _modalSelection;
-    var _selection = select_default2(null);
-    var _dataShortcuts;
-    function shortcutsModal(_modalSelection2) {
-      _modalSelection2.select(".modal").classed("modal-shortcuts", true);
-      var content = _modalSelection2.select(".content");
-      content.append("div").attr("class", "modal-section header").append("h2").call(_t.append("shortcuts.title"));
-      _mainFileFetcher.get("shortcuts").then(function(data) {
-        _dataShortcuts = data;
-        content.call(render);
-      }).catch(function() {
-      });
+  // modules/ui/full_screen.js
+  function uiFullScreen(context) {
+    var element = context.container().node();
+    function getFullScreenFn() {
+      if (element.requestFullscreen) {
+        return element.requestFullscreen;
+      } else if (element.msRequestFullscreen) {
+        return element.msRequestFullscreen;
+      } else if (element.mozRequestFullScreen) {
+        return element.mozRequestFullScreen;
+      } else if (element.webkitRequestFullscreen) {
+        return element.webkitRequestFullscreen;
+      }
     }
-    function render(selection2) {
-      if (!_dataShortcuts)
-        return;
-      var wrapper = selection2.selectAll(".wrapper").data([0]);
-      var wrapperEnter = wrapper.enter().append("div").attr("class", "wrapper modal-section");
-      var tabsBar = wrapperEnter.append("div").attr("class", "tabs-bar");
-      var shortcutsList = wrapperEnter.append("div").attr("class", "shortcuts-list");
-      wrapper = wrapper.merge(wrapperEnter);
-      var tabs = tabsBar.selectAll(".tab").data(_dataShortcuts);
-      var tabsEnter = tabs.enter().append("a").attr("class", "tab").attr("href", "#").on("click", function(d3_event, d) {
-        d3_event.preventDefault();
-        var i2 = _dataShortcuts.indexOf(d);
-        _activeTab = i2;
-        render(selection2);
-      });
-      tabsEnter.append("span").html(function(d) {
-        return _t.html(d.text);
-      });
-      wrapper.selectAll(".tab").classed("active", function(d, i2) {
-        return i2 === _activeTab;
-      });
-      var shortcuts = shortcutsList.selectAll(".shortcut-tab").data(_dataShortcuts);
-      var shortcutsEnter = shortcuts.enter().append("div").attr("class", function(d) {
-        return "shortcut-tab shortcut-tab-" + d.tab;
-      });
-      var columnsEnter = shortcutsEnter.selectAll(".shortcut-column").data(function(d) {
-        return d.columns;
-      }).enter().append("table").attr("class", "shortcut-column");
-      var rowsEnter = columnsEnter.selectAll(".shortcut-row").data(function(d) {
-        return d.rows;
-      }).enter().append("tr").attr("class", "shortcut-row");
-      var sectionRows = rowsEnter.filter(function(d) {
-        return !d.shortcuts;
-      });
-      sectionRows.append("td");
-      sectionRows.append("td").attr("class", "shortcut-section").append("h3").html(function(d) {
-        return _t.html(d.text);
-      });
-      var shortcutRows = rowsEnter.filter(function(d) {
-        return d.shortcuts;
-      });
-      var shortcutKeys = shortcutRows.append("td").attr("class", "shortcut-keys");
-      var modifierKeys = shortcutKeys.filter(function(d) {
-        return d.modifiers;
-      });
-      modifierKeys.selectAll("kbd.modifier").data(function(d) {
-        if (detected.os === "win" && d.text === "shortcuts.editing.commands.redo") {
-          return ["\u2318"];
-        } else if (detected.os !== "mac" && d.text === "shortcuts.browsing.display_options.fullscreen") {
-          return [];
-        } else {
-          return d.modifiers;
-        }
-      }).enter().each(function() {
-        var selection3 = select_default2(this);
-        selection3.append("kbd").attr("class", "modifier").text(function(d) {
-          return uiCmd.display(d);
-        });
-        selection3.append("span").text("+");
-      });
-      shortcutKeys.selectAll("kbd.shortcut").data(function(d) {
-        var arr = d.shortcuts;
-        if (detected.os === "win" && d.text === "shortcuts.editing.commands.redo") {
-          arr = ["Y"];
-        } else if (detected.os !== "mac" && d.text === "shortcuts.browsing.display_options.fullscreen") {
-          arr = ["F11"];
-        }
-        arr = arr.map(function(s) {
-          return uiCmd.display(s.indexOf(".") !== -1 ? _t(s) : s);
-        });
-        return utilArrayUniq(arr).map(function(s) {
-          return {
-            shortcut: s,
-            separator: d.separator,
-            suffix: d.suffix
-          };
-        });
-      }).enter().each(function(d, i2, nodes) {
-        var selection3 = select_default2(this);
-        var click = d.shortcut.toLowerCase().match(/(.*).click/);
-        if (click && click[1]) {
-          selection3.call(svgIcon("#iD-walkthrough-mouse-" + click[1], "operation"));
-        } else if (d.shortcut.toLowerCase() === "long-press") {
-          selection3.call(svgIcon("#iD-walkthrough-longpress", "longpress operation"));
-        } else if (d.shortcut.toLowerCase() === "tap") {
-          selection3.call(svgIcon("#iD-walkthrough-tap", "tap operation"));
-        } else {
-          selection3.append("kbd").attr("class", "shortcut").text(function(d2) {
-            return d2.shortcut;
-          });
-        }
-        if (i2 < nodes.length - 1) {
-          selection3.append("span").html(d.separator || "\xA0" + _t.html("shortcuts.or") + "\xA0");
-        } else if (i2 === nodes.length - 1 && d.suffix) {
-          selection3.append("span").text(d.suffix);
-        }
-      });
-      shortcutKeys.filter(function(d) {
-        return d.gesture;
-      }).each(function() {
-        var selection3 = select_default2(this);
-        selection3.append("span").text("+");
-        selection3.append("span").attr("class", "gesture").html(function(d) {
-          return _t.html(d.gesture);
-        });
-      });
-      shortcutRows.append("td").attr("class", "shortcut-desc").html(function(d) {
-        return d.text ? _t.html(d.text) : "\xA0";
-      });
-      wrapper.selectAll(".shortcut-tab").style("display", function(d, i2) {
-        return i2 === _activeTab ? "flex" : "none";
-      });
+    function getExitFullScreenFn() {
+      if (document.exitFullscreen) {
+        return document.exitFullscreen;
+      } else if (document.msExitFullscreen) {
+        return document.msExitFullscreen;
+      } else if (document.mozCancelFullScreen) {
+        return document.mozCancelFullScreen;
+      } else if (document.webkitExitFullscreen) {
+        return document.webkitExitFullscreen;
+      }
     }
-    return function(selection2, show) {
-      _selection = selection2;
-      if (show) {
-        _modalSelection = uiModal(selection2);
-        _modalSelection.call(shortcutsModal);
+    function isFullScreen() {
+      return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
+    }
+    function isSupported() {
+      return !!getFullScreenFn();
+    }
+    function fullScreen(d3_event) {
+      d3_event.preventDefault();
+      if (!isFullScreen()) {
+        getFullScreenFn().apply(element);
       } else {
-        context.keybinding().on([_t("shortcuts.toggle.key"), "?"], function() {
-          if (context.container().selectAll(".modal-shortcuts").size()) {
-            if (_modalSelection) {
-              _modalSelection.close();
-              _modalSelection = null;
-            }
-          } else {
-            _modalSelection = uiModal(_selection);
-            _modalSelection.call(shortcutsModal);
-          }
-        });
+        getExitFullScreenFn().apply(document);
       }
+    }
+    return function() {
+      if (!isSupported()) return;
+      var detected = utilDetect();
+      var keys2 = detected.os === "mac" ? [uiCmd("\u2303\u2318F"), "f11"] : ["f11"];
+      context.keybinding().on(keys2, fullScreen);
     };
   }
 
-  // modules/ui/data_header.js
-  function uiDataHeader() {
-    var _datum;
-    function dataHeader(selection2) {
-      var header = selection2.selectAll(".data-header").data(
-        _datum ? [_datum] : [],
-        function(d) {
-          return d.__featurehash__;
-        }
-      );
-      header.exit().remove();
-      var headerEnter = header.enter().append("div").attr("class", "data-header");
-      var iconEnter = headerEnter.append("div").attr("class", "data-header-icon");
-      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-data", "note-fill"));
-      headerEnter.append("div").attr("class", "data-header-label").call(_t.append("map_data.layers.custom.title"));
+  // modules/ui/geolocate.js
+  function uiGeolocate(context) {
+    var _geolocationOptions = {
+      // prioritize speed and power usage over precision
+      enableHighAccuracy: false,
+      // don't hang indefinitely getting the location
+      timeout: 6e3
+      // 6sec
+    };
+    var _locating = uiLoading(context).message(_t.html("geolocate.locating")).blocking(true);
+    var _layer = context.layers().layer("geolocate");
+    var _position;
+    var _extent;
+    var _timeoutID;
+    var _button = select_default2(null);
+    function click() {
+      if (context.inIntro()) return;
+      if (!_layer.enabled() && !_locating.isShown()) {
+        _timeoutID = setTimeout(
+          error,
+          1e4
+          /* 10sec */
+        );
+        context.container().call(_locating);
+        navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
+      } else {
+        _locating.close();
+        _layer.enabled(null, false);
+        updateButtonState();
+      }
     }
-    dataHeader.datum = function(val) {
-      if (!arguments.length)
-        return _datum;
-      _datum = val;
-      return this;
+    function zoomTo() {
+      context.enter(modeBrowse(context));
+      var map2 = context.map();
+      _layer.enabled(_position, true);
+      updateButtonState();
+      map2.centerZoomEase(_extent.center(), Math.min(20, map2.extentZoom(_extent)));
+    }
+    function success(geolocation) {
+      _position = geolocation;
+      var coords = _position.coords;
+      _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
+      zoomTo();
+      finish();
+    }
+    function error() {
+      if (_position) {
+        zoomTo();
+      } else {
+        context.ui().flash.label(_t.append("geolocate.location_unavailable")).iconName("#iD-icon-geolocate")();
+      }
+      finish();
+    }
+    function finish() {
+      _locating.close();
+      if (_timeoutID) {
+        clearTimeout(_timeoutID);
+      }
+      _timeoutID = void 0;
+    }
+    function updateButtonState() {
+      _button.classed("active", _layer.enabled());
+      _button.attr("aria-pressed", _layer.enabled());
+    }
+    return function(selection2) {
+      if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
+      _button = selection2.append("button").on("click", click).attr("aria-pressed", false).call(svgIcon("#iD-icon-geolocate", "light")).call(
+        uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _t.append("geolocate.title")).keys([_t("geolocate.key")])
+      );
+      context.keybinding().on(_t("geolocate.key"), click);
     };
-    return dataHeader;
   }
 
-  // modules/ui/combobox.js
-  var _comboHideTimerID;
-  function uiCombobox(context, klass) {
-    var dispatch10 = dispatch_default("accept", "cancel");
-    var container = context.container();
-    var _suggestions = [];
-    var _data = [];
-    var _fetched = {};
-    var _selected = null;
-    var _canAutocomplete = true;
-    var _caseSensitive = false;
-    var _cancelFetch = false;
-    var _minItems = 2;
-    var _tDown = 0;
-    var _mouseEnterHandler, _mouseLeaveHandler;
-    var _fetcher = function(val, cb) {
-      cb(_data.filter(function(d) {
-        var terms = d.terms || [];
-        terms.push(d.value);
-        return terms.some(function(term) {
-          return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
-        });
-      }));
-    };
-    var combobox = function(input, attachTo) {
-      if (!input || input.empty())
-        return;
-      input.classed("combobox-input", true).on("focus.combo-input", focus).on("blur.combo-input", blur).on("keydown.combo-input", keydown).on("keyup.combo-input", keyup).on("input.combo-input", change).on("mousedown.combo-input", mousedown).each(function() {
-        var parent = this.parentNode;
-        var sibling = this.nextSibling;
-        select_default2(parent).selectAll(".combobox-caret").filter(function(d) {
-          return d === input.node();
-        }).data([input.node()]).enter().insert("div", function() {
-          return sibling;
-        }).attr("class", "combobox-caret").on("mousedown.combo-caret", function(d3_event) {
-          d3_event.preventDefault();
-          input.node().focus();
-          mousedown(d3_event);
-        }).on("mouseup.combo-caret", function(d3_event) {
+  // modules/ui/panels/background.js
+  function uiPanelBackground(context) {
+    var background = context.background();
+    var _currSourceName = null;
+    var _metadata = {};
+    var _metadataKeys = [
+      "zoom",
+      "vintage",
+      "source",
+      "description",
+      "resolution",
+      "accuracy"
+    ];
+    var debouncedRedraw = debounce_default(redraw, 250);
+    function redraw(selection2) {
+      var source = background.baseLayerSource();
+      if (!source) return;
+      var isDG = source.id.match(/^DigitalGlobe/i) !== null;
+      var sourceLabel = source.label();
+      if (_currSourceName !== sourceLabel) {
+        _currSourceName = sourceLabel;
+        _metadata = {};
+      }
+      selection2.text("");
+      var list2 = selection2.append("ul").attr("class", "background-info");
+      list2.append("li").call(_currSourceName);
+      _metadataKeys.forEach(function(k2) {
+        if (isDG && k2 === "vintage") return;
+        list2.append("li").attr("class", "background-info-list-" + k2).classed("hide", !_metadata[k2]).call(_t.append("info_panels.background." + k2, { suffix: ":" })).append("span").attr("class", "background-info-span-" + k2).text(_metadata[k2]);
+      });
+      debouncedGetMetadata(selection2);
+      var toggleTiles = context.getDebug("tile") ? "hide_tiles" : "show_tiles";
+      selection2.append("a").call(_t.append("info_panels.background." + toggleTiles)).attr("href", "#").attr("class", "button button-toggle-tiles").on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.setDebug("tile", !context.getDebug("tile"));
+        selection2.call(redraw);
+      });
+      if (isDG) {
+        var key = source.id + "-vintage";
+        var sourceVintage = context.background().findSource(key);
+        var showsVintage = context.background().showsLayer(sourceVintage);
+        var toggleVintage = showsVintage ? "hide_vintage" : "show_vintage";
+        selection2.append("a").call(_t.append("info_panels.background." + toggleVintage)).attr("href", "#").attr("class", "button button-toggle-vintage").on("click", function(d3_event) {
           d3_event.preventDefault();
-          mouseup(d3_event);
+          context.background().toggleOverlayLayer(sourceVintage);
+          selection2.call(redraw);
         });
-      });
-      function mousedown(d3_event) {
-        if (d3_event.button !== 0)
-          return;
-        if (input.classed("disabled"))
-          return;
-        _tDown = +new Date();
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        if (start2 !== end) {
-          var val = utilGetSetValue(input);
-          input.node().setSelectionRange(val.length, val.length);
-          return;
-        }
-        input.on("mouseup.combo-input", mouseup);
       }
-      function mouseup(d3_event) {
-        input.on("mouseup.combo-input", null);
-        if (d3_event.button !== 0)
-          return;
-        if (input.classed("disabled"))
-          return;
-        if (input.node() !== document.activeElement)
-          return;
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        if (start2 !== end)
-          return;
-        var combo = container.selectAll(".combobox");
-        if (combo.empty() || combo.datum() !== input.node()) {
-          var tOrig = _tDown;
-          window.setTimeout(function() {
-            if (tOrig !== _tDown)
-              return;
-            fetchComboData("", function() {
-              show();
-              render();
-            });
-          }, 250);
-        } else {
-          hide();
+      ["DigitalGlobe-Premium", "DigitalGlobe-Standard"].forEach(function(layerId) {
+        if (source.id !== layerId) {
+          var key2 = layerId + "-vintage";
+          var sourceVintage2 = context.background().findSource(key2);
+          if (context.background().showsLayer(sourceVintage2)) {
+            context.background().toggleOverlayLayer(sourceVintage2);
+          }
         }
+      });
+    }
+    var debouncedGetMetadata = debounce_default(getMetadata, 250);
+    function getMetadata(selection2) {
+      var tile = context.container().select(".layer-background img.tile-center");
+      if (tile.empty()) return;
+      var sourceName = _currSourceName;
+      var d2 = tile.datum();
+      var zoom = d2 && d2.length >= 3 && d2[2] || Math.floor(context.map().zoom());
+      var center = context.map().center();
+      _metadata.zoom = String(zoom);
+      selection2.selectAll(".background-info-list-zoom").classed("hide", false).selectAll(".background-info-span-zoom").text(_metadata.zoom);
+      if (!d2 || !d2.length >= 3) return;
+      background.baseLayerSource().getMetadata(center, d2, function(err, result) {
+        if (err || _currSourceName !== sourceName) return;
+        var vintage = result.vintage;
+        _metadata.vintage = vintage && vintage.range || _t("info_panels.background.unknown");
+        selection2.selectAll(".background-info-list-vintage").classed("hide", false).selectAll(".background-info-span-vintage").text(_metadata.vintage);
+        _metadataKeys.forEach(function(k2) {
+          if (k2 === "zoom" || k2 === "vintage") return;
+          var val = result[k2];
+          _metadata[k2] = val;
+          selection2.selectAll(".background-info-list-" + k2).classed("hide", !val).selectAll(".background-info-span-" + k2).text(val);
+        });
+      });
+    }
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.map().on("drawn.info-background", function() {
+        selection2.call(debouncedRedraw);
+      }).on("move.info-background", function() {
+        selection2.call(debouncedGetMetadata);
+      });
+    };
+    panel.off = function() {
+      context.map().on("drawn.info-background", null).on("move.info-background", null);
+    };
+    panel.id = "background";
+    panel.label = _t.append("info_panels.background.title");
+    panel.key = _t("info_panels.background.key");
+    return panel;
+  }
+
+  // modules/ui/panels/history.js
+  function uiPanelHistory(context) {
+    var osm;
+    function displayTimestamp(timestamp) {
+      if (!timestamp) return _t("info_panels.history.unknown");
+      var options2 = {
+        day: "numeric",
+        month: "short",
+        year: "numeric",
+        hour: "numeric",
+        minute: "numeric",
+        second: "numeric"
+      };
+      var d2 = new Date(timestamp);
+      if (isNaN(d2.getTime())) return _t("info_panels.history.unknown");
+      return d2.toLocaleString(_mainLocalizer.localeCode(), options2);
+    }
+    function displayUser(selection2, userName) {
+      if (!userName) {
+        selection2.append("span").call(_t.append("info_panels.history.unknown"));
+        return;
       }
-      function focus() {
-        fetchComboData("");
+      selection2.append("span").attr("class", "user-name").text(userName);
+      var links = selection2.append("div").attr("class", "links");
+      if (osm) {
+        links.append("a").attr("class", "user-osm-link").attr("href", osm.userURL(userName)).attr("target", "_blank").call(_t.append("info_panels.history.profile_link"));
       }
-      function blur() {
-        _comboHideTimerID = window.setTimeout(hide, 75);
+      links.append("a").attr("class", "user-hdyc-link").attr("href", "https://hdyc.neis-one.org/?" + userName).attr("target", "_blank").attr("tabindex", -1).text("HDYC");
+    }
+    function displayChangeset(selection2, changeset) {
+      if (!changeset) {
+        selection2.append("span").call(_t.append("info_panels.history.unknown"));
+        return;
       }
-      function show() {
-        hide();
-        container.insert("div", ":first-child").datum(input.node()).attr("class", "combobox" + (klass ? " combobox-" + klass : "")).style("position", "absolute").style("display", "block").style("left", "0px").on("mousedown.combo-container", function(d3_event) {
-          d3_event.preventDefault();
-        });
-        container.on("scroll.combo-scroll", render, true);
+      selection2.append("span").attr("class", "changeset-id").text(changeset);
+      var links = selection2.append("div").attr("class", "links");
+      if (osm) {
+        links.append("a").attr("class", "changeset-osm-link").attr("href", osm.changesetURL(changeset)).attr("target", "_blank").call(_t.append("info_panels.history.changeset_link"));
       }
-      function hide() {
-        if (_comboHideTimerID) {
-          window.clearTimeout(_comboHideTimerID);
-          _comboHideTimerID = void 0;
+      links.append("a").attr("class", "changeset-osmcha-link").attr("href", "https://osmcha.org/changesets/" + changeset).attr("target", "_blank").text("OSMCha");
+      links.append("a").attr("class", "changeset-achavi-link").attr("href", "https://overpass-api.de/achavi/?changeset=" + changeset).attr("target", "_blank").text("Achavi");
+    }
+    function redraw(selection2) {
+      var selectedNoteID = context.selectedNoteID();
+      osm = context.connection();
+      var selected, note, entity;
+      if (selectedNoteID && osm) {
+        selected = [_t.html("note.note") + " " + selectedNoteID];
+        note = osm.getNote(selectedNoteID);
+      } else {
+        selected = context.selectedIDs().filter(function(e3) {
+          return context.hasEntity(e3);
+        });
+        if (selected.length) {
+          entity = context.entity(selected[0]);
         }
-        container.selectAll(".combobox").remove();
-        container.on("scroll.combo-scroll", null);
       }
-      function keydown(d3_event) {
-        var shown = !container.selectAll(".combobox").empty();
-        var tagName = input.node() ? input.node().tagName.toLowerCase() : "";
-        switch (d3_event.keyCode) {
-          case 8:
-          case 46:
-            d3_event.stopPropagation();
-            _selected = null;
-            render();
-            input.on("input.combo-input", function() {
-              var start2 = input.property("selectionStart");
-              input.node().setSelectionRange(start2, start2);
-              input.on("input.combo-input", change);
-            });
-            break;
-          case 9:
-            accept(d3_event);
-            break;
-          case 13:
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            break;
-          case 38:
-            if (tagName === "textarea" && !shown)
-              return;
-            d3_event.preventDefault();
-            if (tagName === "input" && !shown) {
-              show();
-            }
-            nav(-1);
-            break;
-          case 40:
-            if (tagName === "textarea" && !shown)
-              return;
-            d3_event.preventDefault();
-            if (tagName === "input" && !shown) {
-              show();
-            }
-            nav(1);
-            break;
-        }
+      var singular = selected.length === 1 ? selected[0] : null;
+      selection2.html("");
+      if (singular) {
+        selection2.append("h4").attr("class", "history-heading").html(singular);
+      } else {
+        selection2.append("h4").attr("class", "history-heading").call(_t.append("info_panels.selected", { n: selected.length }));
       }
-      function keyup(d3_event) {
-        switch (d3_event.keyCode) {
-          case 27:
-            cancel();
-            break;
-          case 13:
-            accept(d3_event);
-            break;
-        }
+      if (!singular) return;
+      if (entity) {
+        selection2.call(redrawEntity, entity);
+      } else if (note) {
+        selection2.call(redrawNote, note);
       }
-      function change() {
-        fetchComboData(value(), function() {
-          _selected = null;
-          var val = input.property("value");
-          if (_suggestions.length) {
-            if (input.property("selectionEnd") === val.length) {
-              _selected = tryAutocomplete();
-            }
-            if (!_selected) {
-              _selected = val;
-            }
-          }
-          if (val.length) {
-            var combo = container.selectAll(".combobox");
-            if (combo.empty()) {
-              show();
-            }
-          } else {
-            hide();
-          }
-          render();
-        });
+    }
+    function redrawNote(selection2, note) {
+      if (!note || note.isNew()) {
+        selection2.append("div").call(_t.append("info_panels.history.note_no_history"));
+        return;
       }
-      function nav(dir) {
-        if (_suggestions.length) {
-          var index = -1;
-          for (var i2 = 0; i2 < _suggestions.length; i2++) {
-            if (_selected && _suggestions[i2].value === _selected) {
-              index = i2;
-              break;
-            }
-          }
-          index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
-          _selected = _suggestions[index].value;
-          input.property("value", _selected);
-        }
-        render();
-        ensureVisible();
+      var list2 = selection2.append("ul");
+      list2.append("li").call(_t.append("info_panels.history.note_comments", { suffix: ":" })).append("span").text(note.comments.length);
+      if (note.comments.length) {
+        list2.append("li").call(_t.append("info_panels.history.note_created_date", { suffix: ":" })).append("span").text(displayTimestamp(note.comments[0].date));
+        list2.append("li").call(_t.append("info_panels.history.note_created_user", { suffix: ":" })).call(displayUser, note.comments[0].user);
       }
-      function ensureVisible() {
-        var combo = container.selectAll(".combobox");
-        if (combo.empty())
-          return;
-        var containerRect = container.node().getBoundingClientRect();
-        var comboRect = combo.node().getBoundingClientRect();
-        if (comboRect.bottom > containerRect.bottom) {
-          var node = attachTo ? attachTo.node() : input.node();
-          node.scrollIntoView({ behavior: "instant", block: "center" });
-          render();
-        }
-        var selected = combo.selectAll(".combobox-option.selected").node();
-        if (selected) {
-          selected.scrollIntoView({ behavior: "smooth", block: "nearest" });
-        }
+      if (osm) {
+        selection2.append("a").attr("class", "view-history-on-osm").attr("target", "_blank").attr("href", osm.noteURL(note)).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("info_panels.history.note_link_text"));
       }
-      function value() {
-        var value2 = input.property("value");
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        if (start2 && end) {
-          value2 = value2.substring(0, start2);
-        }
-        return value2;
+    }
+    function redrawEntity(selection2, entity) {
+      if (!entity || entity.isNew()) {
+        selection2.append("div").call(_t.append("info_panels.history.no_history"));
+        return;
       }
-      function fetchComboData(v, cb) {
-        _cancelFetch = false;
-        _fetcher.call(input, v, function(results) {
-          if (_cancelFetch)
-            return;
-          _suggestions = results;
-          results.forEach(function(d) {
-            _fetched[d.value] = d;
-          });
-          if (cb) {
-            cb();
-          }
-        });
+      var links = selection2.append("div").attr("class", "links");
+      if (osm) {
+        links.append("a").attr("class", "view-history-on-osm").attr("href", osm.historyURL(entity)).attr("target", "_blank").call(_t.append("info_panels.history.history_link"));
       }
-      function tryAutocomplete() {
-        if (!_canAutocomplete)
-          return;
-        var val = _caseSensitive ? value() : value().toLowerCase();
-        if (!val)
-          return;
-        if (!isNaN(parseFloat(val)) && isFinite(val))
-          return;
-        var bestIndex = -1;
-        for (var i2 = 0; i2 < _suggestions.length; i2++) {
-          var suggestion = _suggestions[i2].value;
-          var compare = _caseSensitive ? suggestion : suggestion.toLowerCase();
-          if (compare === val) {
-            bestIndex = i2;
-            break;
-          } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
-            bestIndex = i2;
-          }
-        }
-        if (bestIndex !== -1) {
-          var bestVal = _suggestions[bestIndex].value;
-          input.property("value", bestVal);
-          input.node().setSelectionRange(val.length, bestVal.length);
-          return bestVal;
-        }
+      links.append("a").attr("class", "pewu-history-viewer-link").attr("href", "https://pewu.github.io/osm-history/#/" + entity.type + "/" + entity.osmId()).attr("target", "_blank").attr("tabindex", -1).text("PeWu");
+      var list2 = selection2.append("ul");
+      list2.append("li").call(_t.append("info_panels.history.version", { suffix: ":" })).append("span").text(entity.version);
+      list2.append("li").call(_t.append("info_panels.history.last_edit", { suffix: ":" })).append("span").text(displayTimestamp(entity.timestamp));
+      list2.append("li").call(_t.append("info_panels.history.edited_by", { suffix: ":" })).call(displayUser, entity.user);
+      list2.append("li").call(_t.append("info_panels.history.changeset", { suffix: ":" })).call(displayChangeset, entity.changeset);
+    }
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.map().on("drawn.info-history", function() {
+        selection2.call(redraw);
+      });
+      context.on("enter.info-history", function() {
+        selection2.call(redraw);
+      });
+    };
+    panel.off = function() {
+      context.map().on("drawn.info-history", null);
+      context.on("enter.info-history", null);
+    };
+    panel.id = "history";
+    panel.label = _t.append("info_panels.history.title");
+    panel.key = _t("info_panels.history.key");
+    return panel;
+  }
+
+  // modules/ui/panels/location.js
+  function uiPanelLocation(context) {
+    var currLocation = "";
+    function redraw(selection2) {
+      selection2.html("");
+      var list2 = selection2.append("ul");
+      var coord2 = context.map().mouseCoordinates();
+      if (coord2.some(isNaN)) {
+        coord2 = context.map().center();
       }
-      function render() {
-        if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
-          hide();
-          return;
-        }
-        var shown = !container.selectAll(".combobox").empty();
-        if (!shown)
-          return;
-        var combo = container.selectAll(".combobox");
-        var options2 = combo.selectAll(".combobox-option").data(_suggestions, function(d) {
-          return d.value;
+      list2.append("li").text(dmsCoordinatePair(coord2)).append("li").text(decimalCoordinatePair(coord2));
+      selection2.append("div").attr("class", "location-info").text(currLocation || " ");
+      debouncedGetLocation(selection2, coord2);
+    }
+    var debouncedGetLocation = debounce_default(getLocation, 250);
+    function getLocation(selection2, coord2) {
+      if (!services.geocoder) {
+        currLocation = _t("info_panels.location.unknown_location");
+        selection2.selectAll(".location-info").text(currLocation);
+      } else {
+        services.geocoder.reverse(coord2, function(err, result) {
+          currLocation = result ? result.display_name : _t("info_panels.location.unknown_location");
+          selection2.selectAll(".location-info").text(currLocation);
         });
-        options2.exit().remove();
-        options2.enter().append("a").attr("class", function(d) {
-          return "combobox-option " + (d.klass || "");
-        }).attr("title", function(d) {
-          return d.title;
-        }).each(function(d) {
-          if (d.display) {
-            d.display(select_default2(this));
-          } else {
-            select_default2(this).text(d.value);
-          }
-        }).on("mouseenter", _mouseEnterHandler).on("mouseleave", _mouseLeaveHandler).merge(options2).classed("selected", function(d) {
-          return d.value === _selected;
-        }).on("click.combo-option", accept).order();
-        var node = attachTo ? attachTo.node() : input.node();
-        var containerRect = container.node().getBoundingClientRect();
-        var rect = node.getBoundingClientRect();
-        combo.style("left", rect.left + 5 - containerRect.left + "px").style("width", rect.width - 10 + "px").style("top", rect.height + rect.top - containerRect.top + "px");
-      }
-      function accept(d3_event, d) {
-        _cancelFetch = true;
-        var thiz = input.node();
-        if (d) {
-          utilGetSetValue(input, d.value);
-          utilTriggerEvent(input, "change");
-        }
-        var val = utilGetSetValue(input);
-        thiz.setSelectionRange(val.length, val.length);
-        d = _fetched[val];
-        dispatch10.call("accept", thiz, d, val);
-        hide();
-      }
-      function cancel() {
-        _cancelFetch = true;
-        var thiz = input.node();
-        var val = utilGetSetValue(input);
-        var start2 = input.property("selectionStart");
-        var end = input.property("selectionEnd");
-        val = val.slice(0, start2) + val.slice(end);
-        utilGetSetValue(input, val);
-        thiz.setSelectionRange(val.length, val.length);
-        dispatch10.call("cancel", thiz);
-        hide();
       }
+    }
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.surface().on(("PointerEvent" in window ? "pointer" : "mouse") + "move.info-location", function() {
+        selection2.call(redraw);
+      });
     };
-    combobox.canAutocomplete = function(val) {
-      if (!arguments.length)
-        return _canAutocomplete;
-      _canAutocomplete = val;
-      return combobox;
-    };
-    combobox.caseSensitive = function(val) {
-      if (!arguments.length)
-        return _caseSensitive;
-      _caseSensitive = val;
-      return combobox;
-    };
-    combobox.data = function(val) {
-      if (!arguments.length)
-        return _data;
-      _data = val;
-      return combobox;
-    };
-    combobox.fetcher = function(val) {
-      if (!arguments.length)
-        return _fetcher;
-      _fetcher = val;
-      return combobox;
-    };
-    combobox.minItems = function(val) {
-      if (!arguments.length)
-        return _minItems;
-      _minItems = val;
-      return combobox;
-    };
-    combobox.itemsMouseEnter = function(val) {
-      if (!arguments.length)
-        return _mouseEnterHandler;
-      _mouseEnterHandler = val;
-      return combobox;
-    };
-    combobox.itemsMouseLeave = function(val) {
-      if (!arguments.length)
-        return _mouseLeaveHandler;
-      _mouseLeaveHandler = val;
-      return combobox;
+    panel.off = function() {
+      context.surface().on(".info-location", null);
     };
-    return utilRebind(combobox, dispatch10, "on");
+    panel.id = "location";
+    panel.label = _t.append("info_panels.location.title");
+    panel.key = _t("info_panels.location.key");
+    return panel;
   }
-  uiCombobox.off = function(input, context) {
-    input.on("focus.combo-input", null).on("blur.combo-input", null).on("keydown.combo-input", null).on("keyup.combo-input", null).on("input.combo-input", null).on("mousedown.combo-input", null).on("mouseup.combo-input", null);
-    context.container().on("scroll.combo-scroll", null);
-  };
 
-  // modules/ui/disclosure.js
-  function uiDisclosure(context, key, expandedDefault) {
-    var dispatch10 = dispatch_default("toggled");
-    var _expanded;
-    var _label = utilFunctor("");
-    var _updatePreference = true;
-    var _content = function() {
-    };
-    var disclosure = function(selection2) {
-      if (_expanded === void 0 || _expanded === null) {
-        var preference = corePreferences("disclosure." + key + ".expanded");
-        _expanded = preference === null ? !!expandedDefault : preference === "true";
+  // modules/ui/panels/measurement.js
+  function uiPanelMeasurement(context) {
+    function radiansToMeters(r2) {
+      return r2 * 63710071809e-4;
+    }
+    function steradiansToSqmeters(r2) {
+      return r2 / (4 * Math.PI) * 510065621724e3;
+    }
+    function toLineString(feature3) {
+      if (feature3.type === "LineString") return feature3;
+      var result = { type: "LineString", coordinates: [] };
+      if (feature3.type === "Polygon") {
+        result.coordinates = feature3.coordinates[0];
+      } else if (feature3.type === "MultiPolygon") {
+        result.coordinates = feature3.coordinates[0][0];
       }
-      var hideToggle = selection2.selectAll(".hide-toggle-" + key).data([0]);
-      var hideToggleEnter = hideToggle.enter().append("h3").append("a").attr("role", "button").attr("href", "#").attr("class", "hide-toggle hide-toggle-" + key).call(svgIcon("", "pre-text", "hide-toggle-icon"));
-      hideToggleEnter.append("span").attr("class", "hide-toggle-text");
-      hideToggle = hideToggleEnter.merge(hideToggle);
-      hideToggle.on("click", toggle).attr("title", _t(`icons.${_expanded ? "collapse" : "expand"}`)).attr("aria-expanded", _expanded).classed("expanded", _expanded);
-      const label = _label();
-      const labelSelection = hideToggle.selectAll(".hide-toggle-text");
-      if (typeof label !== "function") {
-        labelSelection.text(_label());
+      return result;
+    }
+    var _isImperial = !_mainLocalizer.usesMetric();
+    function redraw(selection2) {
+      var graph = context.graph();
+      var selectedNoteID = context.selectedNoteID();
+      var osm = services.osm;
+      var localeCode = _mainLocalizer.localeCode();
+      var heading2;
+      var center, location, centroid;
+      var closed, geometry;
+      var totalNodeCount, length2 = 0, area = 0, distance;
+      if (selectedNoteID && osm) {
+        var note = osm.getNote(selectedNoteID);
+        heading2 = _t.html("note.note") + " " + selectedNoteID;
+        location = note.loc;
+        geometry = "note";
       } else {
-        labelSelection.text("").call(label);
+        var selectedIDs = context.selectedIDs().filter(function(id2) {
+          return context.hasEntity(id2);
+        });
+        var selected = selectedIDs.map(function(id2) {
+          return context.entity(id2);
+        });
+        heading2 = selected.length === 1 ? selected[0].id : _t.html("info_panels.selected", { n: selected.length });
+        if (selected.length) {
+          var extent = geoExtent();
+          for (var i3 in selected) {
+            var entity = selected[i3];
+            extent._extend(entity.extent(graph));
+            geometry = entity.geometry(graph);
+            if (geometry === "line" || geometry === "area") {
+              closed = entity.type === "relation" || entity.isClosed() && !entity.isDegenerate();
+              var feature3 = entity.asGeoJSON(graph);
+              length2 += radiansToMeters(length_default(toLineString(feature3)));
+              centroid = path_default(context.projection).centroid(entity.asGeoJSON(graph));
+              centroid = centroid && context.projection.invert(centroid);
+              if (!centroid || !isFinite(centroid[0]) || !isFinite(centroid[1])) {
+                centroid = entity.extent(graph).center();
+              }
+              if (closed) {
+                area += steradiansToSqmeters(entity.area(graph));
+              }
+            }
+          }
+          if (selected.length > 1) {
+            geometry = null;
+            closed = null;
+            centroid = null;
+          }
+          if (selected.length === 2 && selected[0].type === "node" && selected[1].type === "node") {
+            distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
+          }
+          if (selected.length === 1 && selected[0].type === "node") {
+            location = selected[0].loc;
+          } else {
+            totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
+          }
+          if (!location && !centroid) {
+            center = extent.center();
+          }
+        }
       }
-      hideToggle.selectAll(".hide-toggle-icon").attr(
-        "xlink:href",
-        _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
-      );
-      var wrap2 = selection2.selectAll(".disclosure-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "disclosure-wrap disclosure-wrap-" + key).merge(wrap2).classed("hide", !_expanded);
-      if (_expanded) {
-        wrap2.call(_content);
+      selection2.html("");
+      if (heading2) {
+        selection2.append("h4").attr("class", "measurement-heading").html(heading2);
       }
-      function toggle(d3_event) {
-        d3_event.preventDefault();
-        _expanded = !_expanded;
-        if (_updatePreference) {
-          corePreferences("disclosure." + key + ".expanded", _expanded);
-        }
-        hideToggle.classed("expanded", _expanded).attr("aria-expanded", _expanded).attr("title", _t(`icons.${_expanded ? "collapse" : "expand"}`));
-        hideToggle.selectAll(".hide-toggle-icon").attr(
-          "xlink:href",
-          _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
+      var list2 = selection2.append("ul");
+      var coordItem;
+      if (geometry) {
+        list2.append("li").call(_t.append("info_panels.measurement.geometry", { suffix: ":" })).append("span").html(
+          closed ? _t.html("info_panels.measurement.closed_" + geometry) : _t.html("geometry." + geometry)
         );
-        wrap2.call(uiToggle(_expanded));
-        if (_expanded) {
-          wrap2.call(_content);
-        }
-        dispatch10.call("toggled", this, _expanded);
       }
-    };
-    disclosure.label = function(val) {
-      if (!arguments.length)
-        return _label;
-      _label = utilFunctor(val);
-      return disclosure;
-    };
-    disclosure.expanded = function(val) {
-      if (!arguments.length)
-        return _expanded;
-      _expanded = val;
-      return disclosure;
-    };
-    disclosure.updatePreference = function(val) {
-      if (!arguments.length)
-        return _updatePreference;
-      _updatePreference = val;
-      return disclosure;
-    };
-    disclosure.content = function(val) {
-      if (!arguments.length)
-        return _content;
-      _content = val;
-      return disclosure;
-    };
-    return utilRebind(disclosure, dispatch10, "on");
-  }
-
-  // modules/ui/section.js
-  function uiSection(id2, context) {
-    var _classes = utilFunctor("");
-    var _shouldDisplay;
-    var _content;
-    var _disclosure;
-    var _label;
-    var _expandedByDefault = utilFunctor(true);
-    var _disclosureContent;
-    var _disclosureExpanded;
-    var _containerSelection = select_default2(null);
-    var section = {
-      id: id2
-    };
-    section.classes = function(val) {
-      if (!arguments.length)
-        return _classes;
-      _classes = utilFunctor(val);
-      return section;
-    };
-    section.label = function(val) {
-      if (!arguments.length)
-        return _label;
-      _label = utilFunctor(val);
-      return section;
-    };
-    section.expandedByDefault = function(val) {
-      if (!arguments.length)
-        return _expandedByDefault;
-      _expandedByDefault = utilFunctor(val);
-      return section;
-    };
-    section.shouldDisplay = function(val) {
-      if (!arguments.length)
-        return _shouldDisplay;
-      _shouldDisplay = utilFunctor(val);
-      return section;
-    };
-    section.content = function(val) {
-      if (!arguments.length)
-        return _content;
-      _content = val;
-      return section;
-    };
-    section.disclosureContent = function(val) {
-      if (!arguments.length)
-        return _disclosureContent;
-      _disclosureContent = val;
-      return section;
-    };
-    section.disclosureExpanded = function(val) {
-      if (!arguments.length)
-        return _disclosureExpanded;
-      _disclosureExpanded = val;
-      return section;
-    };
-    section.render = function(selection2) {
-      _containerSelection = selection2.selectAll(".section-" + id2).data([0]);
-      var sectionEnter = _containerSelection.enter().append("div").attr("class", "section section-" + id2 + " " + (_classes && _classes() || ""));
-      _containerSelection = sectionEnter.merge(_containerSelection);
-      _containerSelection.call(renderContent);
-    };
-    section.reRender = function() {
-      _containerSelection.call(renderContent);
-    };
-    section.selection = function() {
-      return _containerSelection;
-    };
-    section.disclosure = function() {
-      return _disclosure;
-    };
-    function renderContent(selection2) {
-      if (_shouldDisplay) {
-        var shouldDisplay = _shouldDisplay();
-        selection2.classed("hide", !shouldDisplay);
-        if (!shouldDisplay) {
-          selection2.html("");
-          return;
-        }
+      if (totalNodeCount) {
+        list2.append("li").call(_t.append("info_panels.measurement.node_count", { suffix: ":" })).append("span").text(totalNodeCount.toLocaleString(localeCode));
       }
-      if (_disclosureContent) {
-        if (!_disclosure) {
-          _disclosure = uiDisclosure(context, id2.replace(/-/g, "_"), _expandedByDefault()).label(_label || "").content(_disclosureContent);
-        }
-        if (_disclosureExpanded !== void 0) {
-          _disclosure.expanded(_disclosureExpanded);
-          _disclosureExpanded = void 0;
-        }
-        selection2.call(_disclosure);
-        return;
+      if (area) {
+        list2.append("li").call(_t.append("info_panels.measurement.area", { suffix: ":" })).append("span").text(displayArea(area, _isImperial));
       }
-      if (_content) {
-        selection2.call(_content);
+      if (length2) {
+        list2.append("li").call(_t.append("info_panels.measurement." + (closed ? "perimeter" : "length"), { suffix: ":" })).append("span").text(displayLength(length2, _isImperial));
       }
-    }
-    return section;
-  }
-
-  // modules/ui/tag_reference.js
-  function uiTagReference(what) {
-    var wikibase = what.qid ? services.wikidata : services.osmWikibase;
-    var tagReference = {};
-    var _button = select_default2(null);
-    var _body = select_default2(null);
-    var _loaded;
-    var _showing;
-    function load() {
-      if (!wikibase)
-        return;
-      _button.classed("tag-reference-loading", true);
-      wikibase.getDocs(what, gotDocs);
-    }
-    function gotDocs(err, docs) {
-      _body.html("");
-      if (!docs || !docs.title) {
-        _body.append("p").attr("class", "tag-reference-description").call(_t.append("inspector.no_documentation_key"));
-        done();
-        return;
+      if (typeof distance === "number") {
+        list2.append("li").call(_t.append("info_panels.measurement.distance", { suffix: ":" })).append("span").text(displayLength(distance, _isImperial));
       }
-      if (docs.imageURL) {
-        _body.append("img").attr("class", "tag-reference-wiki-image").attr("alt", docs.description).attr("src", docs.imageURL).on("load", function() {
-          done();
-        }).on("error", function() {
-          select_default2(this).remove();
-          done();
-        });
-      } else {
-        done();
+      if (location) {
+        coordItem = list2.append("li").call(_t.append("info_panels.measurement.location", { suffix: ":" }));
+        coordItem.append("span").text(dmsCoordinatePair(location));
+        coordItem.append("span").text(decimalCoordinatePair(location));
       }
-      var tagReferenceDescription = _body.append("p").attr("class", "tag-reference-description").append("span");
-      if (docs.description) {
-        tagReferenceDescription = tagReferenceDescription.attr("class", "localized-text").attr("lang", docs.descriptionLocaleCode || "und").text(docs.description);
-      } else {
-        tagReferenceDescription = tagReferenceDescription.call(_t.append("inspector.no_documentation_key"));
+      if (centroid) {
+        coordItem = list2.append("li").call(_t.append("info_panels.measurement.centroid", { suffix: ":" }));
+        coordItem.append("span").text(dmsCoordinatePair(centroid));
+        coordItem.append("span").text(decimalCoordinatePair(centroid));
       }
-      tagReferenceDescription.append("a").attr("class", "tag-reference-edit").attr("target", "_blank").attr("title", _t("inspector.edit_reference")).attr("href", docs.editURL).call(svgIcon("#iD-icon-edit", "inline"));
-      if (docs.wiki) {
-        _body.append("a").attr("class", "tag-reference-link").attr("target", "_blank").attr("href", docs.wiki.url).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append(docs.wiki.text));
+      if (center) {
+        coordItem = list2.append("li").call(_t.append("info_panels.measurement.center", { suffix: ":" }));
+        coordItem.append("span").text(dmsCoordinatePair(center));
+        coordItem.append("span").text(decimalCoordinatePair(center));
       }
-      if (what.key === "comment") {
-        _body.append("a").attr("class", "tag-reference-comment-link").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", _t("commit.about_changeset_comments_link")).append("span").call(_t.append("commit.about_changeset_comments"));
+      if (length2 || area || typeof distance === "number") {
+        var toggle = _isImperial ? "imperial" : "metric";
+        selection2.append("a").call(_t.append("info_panels.measurement." + toggle)).attr("href", "#").attr("class", "button button-toggle-units").on("click", function(d3_event) {
+          d3_event.preventDefault();
+          _isImperial = !_isImperial;
+          selection2.call(redraw);
+        });
       }
     }
-    function done() {
-      _loaded = true;
-      _button.classed("tag-reference-loading", false);
-      _body.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1");
-      _showing = true;
-      _button.selectAll("svg.icon use").each(function() {
-        var iconUse = select_default2(this);
-        if (iconUse.attr("href") === "#iD-icon-info") {
-          iconUse.attr("href", "#iD-icon-info-filled");
-        }
-      });
-    }
-    function hide() {
-      _body.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
-        _body.classed("expanded", false);
-      });
-      _showing = false;
-      _button.selectAll("svg.icon use").each(function() {
-        var iconUse = select_default2(this);
-        if (iconUse.attr("href") === "#iD-icon-info-filled") {
-          iconUse.attr("href", "#iD-icon-info");
-        }
-      });
-    }
-    tagReference.button = function(selection2, klass, iconName) {
-      _button = selection2.selectAll(".tag-reference-button").data([0]);
-      _button = _button.enter().append("button").attr("class", "tag-reference-button " + (klass || "")).attr("title", _t("icons.information")).call(svgIcon("#iD-icon-" + (iconName || "inspect"))).merge(_button);
-      _button.on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        this.blur();
-        if (_showing) {
-          hide();
-        } else if (_loaded) {
-          done();
-        } else {
-          load();
-        }
+    var panel = function(selection2) {
+      selection2.call(redraw);
+      context.map().on("drawn.info-measurement", function() {
+        selection2.call(redraw);
       });
-    };
-    tagReference.body = function(selection2) {
-      var itemID = what.qid || what.key + "-" + (what.value || "");
-      _body = selection2.selectAll(".tag-reference-body").data([itemID], function(d) {
-        return d;
+      context.on("enter.info-measurement", function() {
+        selection2.call(redraw);
       });
-      _body.exit().remove();
-      _body = _body.enter().append("div").attr("class", "tag-reference-body").style("max-height", "0").style("opacity", "0").merge(_body);
-      if (_showing === false) {
-        hide();
-      }
     };
-    tagReference.showing = function(val) {
-      if (!arguments.length)
-        return _showing;
-      _showing = val;
-      return tagReference;
+    panel.off = function() {
+      context.map().on("drawn.info-measurement", null);
+      context.on("enter.info-measurement", null);
     };
-    return tagReference;
+    panel.id = "measurement";
+    panel.label = _t.append("info_panels.measurement.title");
+    panel.key = _t("info_panels.measurement.key");
+    return panel;
   }
 
-  // modules/ui/field_help.js
-  function uiFieldHelp(context, fieldName) {
-    var fieldHelp = {};
-    var _inspector = select_default2(null);
-    var _wrap = select_default2(null);
-    var _body = select_default2(null);
-    var fieldHelpKeys = {
-      restrictions: [
-        ["about", [
-          "about",
-          "from_via_to",
-          "maxdist",
-          "maxvia"
-        ]],
-        ["inspecting", [
-          "about",
-          "from_shadow",
-          "allow_shadow",
-          "restrict_shadow",
-          "only_shadow",
-          "restricted",
-          "only"
-        ]],
-        ["modifying", [
-          "about",
-          "indicators",
-          "allow_turn",
-          "restrict_turn",
-          "only_turn"
-        ]],
-        ["tips", [
-          "simple",
-          "simple_example",
-          "indirect",
-          "indirect_example",
-          "indirect_noedit"
-        ]]
-      ]
-    };
-    var fieldHelpHeadings = {};
-    var replacements = {
-      distField: { html: _t.html("restriction.controls.distance") },
-      viaField: { html: _t.html("restriction.controls.via") },
-      fromShadow: { html: icon("#iD-turn-shadow", "inline shadow from") },
-      allowShadow: { html: icon("#iD-turn-shadow", "inline shadow allow") },
-      restrictShadow: { html: icon("#iD-turn-shadow", "inline shadow restrict") },
-      onlyShadow: { html: icon("#iD-turn-shadow", "inline shadow only") },
-      allowTurn: { html: icon("#iD-turn-yes", "inline turn") },
-      restrictTurn: { html: icon("#iD-turn-no", "inline turn") },
-      onlyTurn: { html: icon("#iD-turn-only", "inline turn") }
-    };
-    var docs = fieldHelpKeys[fieldName].map(function(key) {
-      var helpkey = "help.field." + fieldName + "." + key[0];
-      var text2 = key[1].reduce(function(all, part) {
-        var subkey = helpkey + "." + part;
-        var depth = fieldHelpHeadings[subkey];
-        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
-        return all + hhh + _t.html(subkey, replacements) + "\n\n";
-      }, "");
-      return {
-        key: helpkey,
-        title: _t.html(helpkey + ".title"),
-        html: marked(text2.trim())
-      };
+  // modules/ui/panels/index.js
+  var uiInfoPanels = {
+    background: uiPanelBackground,
+    history: uiPanelHistory,
+    location: uiPanelLocation,
+    measurement: uiPanelMeasurement
+  };
+
+  // modules/ui/info.js
+  function uiInfo(context) {
+    var ids = Object.keys(uiInfoPanels);
+    var wasActive = ["measurement"];
+    var panels = {};
+    var active = {};
+    ids.forEach(function(k2) {
+      if (!panels[k2]) {
+        panels[k2] = uiInfoPanels[k2](context);
+        active[k2] = false;
+      }
     });
-    function show() {
-      updatePosition();
-      _body.classed("hide", false).style("opacity", "0").transition().duration(200).style("opacity", "1");
-    }
-    function hide() {
-      _body.classed("hide", true).transition().duration(200).style("opacity", "0").on("end", function() {
-        _body.classed("hide", true);
-      });
-    }
-    function clickHelp(index) {
-      var d = docs[index];
-      var tkeys = fieldHelpKeys[fieldName][index][1];
-      _body.selectAll(".field-help-nav-item").classed("active", function(d2, i2) {
-        return i2 === index;
-      });
-      var content = _body.selectAll(".field-help-content").html(d.html);
-      content.selectAll("p").attr("class", function(d2, i2) {
-        return tkeys[i2];
-      });
-      if (d.key === "help.field.restrictions.inspecting") {
-        content.insert("img", "p.from_shadow").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_inspect.gif"));
-      } else if (d.key === "help.field.restrictions.modifying") {
-        content.insert("img", "p.allow_turn").attr("class", "field-help-image cf").attr("src", context.imagePath("tr_modify.gif"));
+    function info(selection2) {
+      function redraw() {
+        var activeids = ids.filter(function(k2) {
+          return active[k2];
+        }).sort();
+        var containers = infoPanels.selectAll(".panel-container").data(activeids, function(k2) {
+          return k2;
+        });
+        containers.exit().style("opacity", 1).transition().duration(200).style("opacity", 0).on("end", function(d2) {
+          select_default2(this).call(panels[d2].off).remove();
+        });
+        var enter = containers.enter().append("div").attr("class", function(d2) {
+          return "fillD2 panel-container panel-container-" + d2;
+        });
+        enter.style("opacity", 0).transition().duration(200).style("opacity", 1);
+        var title = enter.append("div").attr("class", "panel-title fillD2");
+        title.append("h3").each(function(d2) {
+          return panels[d2].label(select_default2(this));
+        });
+        title.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function(d3_event, d2) {
+          d3_event.stopImmediatePropagation();
+          d3_event.preventDefault();
+          info.toggle(d2);
+        }).call(svgIcon("#iD-icon-close"));
+        enter.append("div").attr("class", function(d2) {
+          return "panel-content panel-content-" + d2;
+        });
+        infoPanels.selectAll(".panel-content").each(function(d2) {
+          select_default2(this).call(panels[d2]);
+        });
       }
-    }
-    fieldHelp.button = function(selection2) {
-      if (_body.empty())
-        return;
-      var button = selection2.selectAll(".field-help-button").data([0]);
-      button.enter().append("button").attr("class", "field-help-button").call(svgIcon("#iD-icon-help")).merge(button).on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        if (_body.classed("hide")) {
-          show();
+      info.toggle = function(which) {
+        var activeids = ids.filter(function(k2) {
+          return active[k2];
+        });
+        if (which) {
+          active[which] = !active[which];
+          if (activeids.length === 1 && activeids[0] === which) {
+            wasActive = [which];
+          }
+          context.container().select("." + which + "-panel-toggle-item").classed("active", active[which]).select("input").property("checked", active[which]);
         } else {
-          hide();
+          if (activeids.length) {
+            wasActive = activeids;
+            activeids.forEach(function(k2) {
+              active[k2] = false;
+            });
+          } else {
+            wasActive.forEach(function(k2) {
+              active[k2] = true;
+            });
+          }
         }
-      });
-    };
-    function updatePosition() {
-      var wrap2 = _wrap.node();
-      var inspector = _inspector.node();
-      var wRect = wrap2.getBoundingClientRect();
-      var iRect = inspector.getBoundingClientRect();
-      _body.style("top", wRect.top + inspector.scrollTop - iRect.top + "px");
-    }
-    fieldHelp.body = function(selection2) {
-      _wrap = selection2.selectAll(".form-field-input-wrap");
-      if (_wrap.empty())
-        return;
-      _inspector = context.container().select(".sidebar .entity-editor-pane .inspector-body");
-      if (_inspector.empty())
-        return;
-      _body = _inspector.selectAll(".field-help-body").data([0]);
-      var enter = _body.enter().append("div").attr("class", "field-help-body hide");
-      var titleEnter = enter.append("div").attr("class", "field-help-title cf");
-      titleEnter.append("h2").attr("class", _mainLocalizer.textDirection() === "rtl" ? "fr" : "fl").call(_t.append("help.field." + fieldName + ".title"));
-      titleEnter.append("button").attr("class", "fr close").attr("title", _t("icons.close")).on("click", function(d3_event) {
-        d3_event.stopPropagation();
+        redraw();
+      };
+      var infoPanels = selection2.selectAll(".info-panels").data([0]);
+      infoPanels = infoPanels.enter().append("div").attr("class", "info-panels").merge(infoPanels);
+      redraw();
+      context.keybinding().on(uiCmd("\u2318" + _t("info_panels.key")), function(d3_event) {
+        d3_event.stopImmediatePropagation();
         d3_event.preventDefault();
-        hide();
-      }).call(svgIcon("#iD-icon-close"));
-      var navEnter = enter.append("div").attr("class", "field-help-nav cf");
-      var titles = docs.map(function(d) {
-        return d.title;
+        info.toggle();
       });
-      navEnter.selectAll(".field-help-nav-item").data(titles).enter().append("div").attr("class", "field-help-nav-item").html(function(d) {
-        return d;
-      }).on("click", function(d3_event, d) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        clickHelp(titles.indexOf(d));
+      ids.forEach(function(k2) {
+        var key = _t("info_panels." + k2 + ".key", { default: null });
+        if (!key) return;
+        context.keybinding().on(uiCmd("\u2318\u21E7" + key), function(d3_event) {
+          d3_event.stopImmediatePropagation();
+          d3_event.preventDefault();
+          info.toggle(k2);
+        });
+      });
+    }
+    return info;
+  }
+
+  // modules/ui/toggle.js
+  function uiToggle(show, callback) {
+    return function(selection2) {
+      selection2.style("opacity", show ? 0 : 1).classed("hide", false).transition().style("opacity", show ? 1 : 0).on("end", function() {
+        select_default2(this).classed("hide", !show).style("opacity", null);
+        if (callback) callback.apply(this);
       });
-      enter.append("div").attr("class", "field-help-content");
-      _body = _body.merge(enter);
-      clickHelp(0);
     };
-    return fieldHelp;
   }
 
-  // modules/ui/fields/check.js
-  function uiFieldCheck(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var options2 = field.options;
-    var values = [];
-    var texts = [];
-    var _tags;
-    var input = select_default2(null);
-    var text2 = select_default2(null);
-    var label = select_default2(null);
-    var reverser = select_default2(null);
-    var _impliedYes;
-    var _entityIDs = [];
-    var _value;
-    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 }));
-      }
-    } else {
-      values = [void 0, "yes"];
-      texts = [_t.html("inspector.unknown"), _t.html("inspector.check.yes")];
-      if (field.type !== "defaultCheck") {
-        values.push("no");
-        texts.push(_t.html("inspector.check.no"));
+  // modules/ui/curtain.js
+  function uiCurtain(containerNode) {
+    var surface = select_default2(null), tooltip = select_default2(null), darkness = select_default2(null);
+    function curtain(selection2) {
+      surface = selection2.append("svg").attr("class", "curtain").style("top", 0).style("left", 0);
+      darkness = surface.append("path").attr("x", 0).attr("y", 0).attr("class", "curtain-darkness");
+      select_default2(window).on("resize.curtain", resize);
+      tooltip = selection2.append("div").attr("class", "tooltip");
+      tooltip.append("div").attr("class", "popover-arrow");
+      tooltip.append("div").attr("class", "popover-inner");
+      resize();
+      function resize() {
+        surface.attr("width", containerNode.clientWidth).attr("height", containerNode.clientHeight);
+        curtain.cut(darkness.datum());
       }
     }
-    function checkImpliedYes() {
-      _impliedYes = field.id === "oneway_yes";
-      if (field.id === "oneway") {
-        var entity = context.entity(_entityIDs[0]);
-        for (var key in entity.tags) {
-          if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
-            _impliedYes = true;
-            texts[0] = _t.html("_tagging.presets.fields.oneway_yes.options.undefined");
-            break;
-          }
-        }
+    curtain.reveal = function(box, html3, options2) {
+      options2 = options2 || {};
+      if (typeof box === "string") {
+        box = select_default2(box).node();
       }
-    }
-    function reverserHidden() {
-      if (!context.container().select("div.inspector-hover").empty())
-        return true;
-      return !(_value === "yes" || _impliedYes && !_value);
-    }
-    function reverserSetText(selection2) {
-      var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
-      if (reverserHidden() || !entity)
-        return selection2;
-      var first = entity.first();
-      var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
-      var pseudoDirection = first < last;
-      var icon2 = pseudoDirection ? "#iD-icon-forward" : "#iD-icon-backward";
-      selection2.selectAll(".reverser-span").html("").call(_t.append("inspector.check.reverser")).call(svgIcon(icon2, "inline"));
-      return selection2;
-    }
-    var check = function(selection2) {
-      checkImpliedYes();
-      label = selection2.selectAll(".form-field-input-wrap").data([0]);
-      var enter = label.enter().append("label").attr("class", "form-field-input-wrap form-field-input-check");
-      enter.append("input").property("indeterminate", field.type !== "defaultCheck").attr("type", "checkbox").attr("id", field.domId);
-      enter.append("span").html(texts[0]).attr("class", "value");
-      if (field.type === "onewayCheck") {
-        enter.append("button").attr("class", "reverser" + (reverserHidden() ? " hide" : "")).append("span").attr("class", "reverser-span");
+      if (box && box.getBoundingClientRect) {
+        box = copyBox(box.getBoundingClientRect());
+        var containerRect = containerNode.getBoundingClientRect();
+        box.top -= containerRect.top;
+        box.left -= containerRect.left;
       }
-      label = label.merge(enter);
-      input = label.selectAll("input");
-      text2 = label.selectAll("span.value");
-      input.on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        var t = {};
-        if (Array.isArray(_tags[field.key])) {
-          if (values.indexOf("yes") !== -1) {
-            t[field.key] = "yes";
+      if (box && options2.padding) {
+        box.top -= options2.padding;
+        box.left -= options2.padding;
+        box.bottom += options2.padding;
+        box.right += options2.padding;
+        box.height += options2.padding * 2;
+        box.width += options2.padding * 2;
+      }
+      var tooltipBox;
+      if (options2.tooltipBox) {
+        tooltipBox = options2.tooltipBox;
+        if (typeof tooltipBox === "string") {
+          tooltipBox = select_default2(tooltipBox).node();
+        }
+        if (tooltipBox && tooltipBox.getBoundingClientRect) {
+          tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
+        }
+      } else {
+        tooltipBox = box;
+      }
+      if (tooltipBox && html3) {
+        if (html3.indexOf("**") !== -1) {
+          if (html3.indexOf("<span") === 0) {
+            html3 = html3.replace(/^(<span.*?>)(.+?)(\*\*)/, "$1<span>$2</span>$3");
           } else {
-            t[field.key] = values[0];
+            html3 = html3.replace(/^(.+?)(\*\*)/, "<span>$1</span>$2");
           }
+          html3 = html3.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
+        }
+        html3 = html3.replace(/\*(.*?)\*/g, "<em>$1</em>");
+        html3 = html3.replace(/\{br\}/g, "<br/><br/>");
+        if (options2.buttonText && options2.buttonCallback) {
+          html3 += '<div class="button-section"><button href="#" class="button action">' + options2.buttonText + "</button></div>";
+        }
+        var classes = "curtain-tooltip popover tooltip arrowed in " + (options2.tooltipClass || "");
+        tooltip.classed(classes, true).selectAll(".popover-inner").html(html3);
+        if (options2.buttonText && options2.buttonCallback) {
+          var button = tooltip.selectAll(".button-section .button.action");
+          button.on("click", function(d3_event) {
+            d3_event.preventDefault();
+            options2.buttonCallback();
+          });
+        }
+        var tip = copyBox(tooltip.node().getBoundingClientRect()), w2 = containerNode.clientWidth, h2 = containerNode.clientHeight, tooltipWidth = 200, tooltipArrow = 5, side, pos;
+        if (options2.tooltipClass === "intro-mouse") {
+          tip.height += 80;
+        }
+        if (tooltipBox.top + tooltipBox.height > h2) {
+          tooltipBox.height -= tooltipBox.top + tooltipBox.height - h2;
+        }
+        if (tooltipBox.left + tooltipBox.width > w2) {
+          tooltipBox.width -= tooltipBox.left + tooltipBox.width - w2;
+        }
+        if (tooltipBox.top + tooltipBox.height < 100) {
+          side = "bottom";
+          pos = [
+            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
+            tooltipBox.top + tooltipBox.height
+          ];
+        } else if (tooltipBox.top > h2 - 140) {
+          side = "top";
+          pos = [
+            tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
+            tooltipBox.top - tip.height
+          ];
         } else {
-          t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
+          var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
+          if (_mainLocalizer.textDirection() === "rtl") {
+            if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
+              side = "right";
+              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
+            } else {
+              side = "left";
+              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
+            }
+          } else {
+            if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w2 - 70) {
+              side = "left";
+              pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
+            } else {
+              side = "right";
+              pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
+            }
+          }
         }
-        if (t[field.key] === "reversible" || t[field.key] === "alternating") {
-          t[field.key] = values[0];
+        if (options2.duration !== 0 || !tooltip.classed(side)) {
+          tooltip.call(uiToggle(true));
         }
-        dispatch10.call("change", this, t);
-      });
-      if (field.type === "onewayCheck") {
-        reverser = label.selectAll(".reverser");
-        reverser.call(reverserSetText).on("click", function(d3_event) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          context.perform(
-            function(graph) {
-              for (var i3 in _entityIDs) {
-                graph = actionReverse(_entityIDs[i3])(graph);
-              }
-              return graph;
-            },
-            _t("operations.reverse.annotation.line", { n: 1 })
-          );
-          context.validator().validate();
-          select_default2(this).call(reverserSetText);
-        });
+        tooltip.style("top", pos[1] + "px").style("left", pos[0] + "px").attr("class", classes + " " + side);
+        var shiftY = 0;
+        if (side === "left" || side === "right") {
+          if (pos[1] < 60) {
+            shiftY = 60 - pos[1];
+          } else if (pos[1] + tip.height > h2 - 100) {
+            shiftY = h2 - pos[1] - tip.height - 100;
+          }
+        }
+        tooltip.selectAll(".popover-inner").style("top", shiftY + "px");
+      } else {
+        tooltip.classed("in", false).call(uiToggle(false));
       }
+      curtain.cut(box, options2.duration);
+      return tooltip;
     };
-    check.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return check;
-    };
-    check.tags = function(tags) {
-      _tags = tags;
-      function isChecked(val) {
-        return val !== "no" && val !== "" && val !== void 0 && val !== null;
-      }
-      function textFor(val) {
-        if (val === "")
-          val = void 0;
-        var index = values.indexOf(val);
-        return index !== -1 ? texts[index] : '"' + val + '"';
-      }
-      checkImpliedYes();
-      var isMixed = Array.isArray(tags[field.key]);
-      _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
-      if (field.type === "onewayCheck" && (_value === "1" || _value === "-1")) {
-        _value = "yes";
-      }
-      input.property("indeterminate", isMixed || field.type !== "defaultCheck" && !_value).property("checked", isChecked(_value));
-      text2.html(isMixed ? _t.html("inspector.multiple_values") : textFor(_value)).classed("mixed", isMixed);
-      label.classed("set", !!_value);
-      if (field.type === "onewayCheck") {
-        reverser.classed("hide", reverserHidden()).call(reverserSetText);
+    curtain.cut = function(datum2, duration) {
+      darkness.datum(datum2).interrupt();
+      var selection2;
+      if (duration === 0) {
+        selection2 = darkness;
+      } else {
+        selection2 = darkness.transition().duration(duration || 600).ease(linear2);
       }
+      selection2.attr("d", function(d2) {
+        var containerWidth = containerNode.clientWidth;
+        var containerHeight = containerNode.clientHeight;
+        var string = "M 0,0 L 0," + containerHeight + " L " + containerWidth + "," + containerHeight + "L" + containerWidth + ",0 Z";
+        if (!d2) return string;
+        return string + "M" + d2.left + "," + d2.top + "L" + d2.left + "," + (d2.top + d2.height) + "L" + (d2.left + d2.width) + "," + (d2.top + d2.height) + "L" + (d2.left + d2.width) + "," + d2.top + "Z";
+      });
     };
-    check.focus = function() {
-      input.node().focus();
+    curtain.remove = function() {
+      surface.remove();
+      tooltip.remove();
+      select_default2(window).on("resize.curtain", null);
     };
-    return utilRebind(check, dispatch10, "on");
+    function copyBox(src) {
+      return {
+        top: src.top,
+        right: src.right,
+        bottom: src.bottom,
+        left: src.left,
+        width: src.width,
+        height: src.height
+      };
+    }
+    return curtain;
   }
 
-  // modules/ui/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 _container = select_default2(null);
-    var _inputWrap = select_default2(null);
-    var _input = select_default2(null);
-    var _comboData = [];
-    var _multiData = [];
-    var _entityIDs = [];
-    var _tags;
-    var _countryCode;
-    var _staticPlaceholder;
-    var _dataDeprecated = [];
-    _mainFileFetcher.get("deprecated").then(function(d) {
-      _dataDeprecated = d;
-    }).catch(function() {
-    });
-    if (_isMulti && field.key && /[^:]$/.test(field.key)) {
-      field.key += ":";
-    }
-    function snake(s) {
-      return s.replace(/\s+/g, "_").toLowerCase();
-    }
-    function clean2(s) {
-      return s.split(";").map(function(s2) {
-        return s2.trim();
-      }).join(";");
+  // modules/ui/intro/welcome.js
+  function uiIntroWelcome(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var chapter = {
+      title: "intro.welcome.title"
+    };
+    function welcome() {
+      context.map().centerZoom([-85.63591, 41.94285], 19);
+      reveal(
+        ".intro-nav-wrap .chapter-welcome",
+        helpHtml("intro.welcome.welcome"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: practice }
+      );
     }
-    function tagValue(dval) {
-      dval = clean2(dval || "");
-      var found = _comboData.find(function(o) {
-        return o.key && clean2(o.value) === dval;
-      });
-      if (found)
-        return found.key;
-      if (field.type === "typeCombo" && !dval) {
-        return "yes";
-      }
-      return (_snake_case ? snake(dval) : dval) || void 0;
+    function practice() {
+      reveal(
+        ".intro-nav-wrap .chapter-welcome",
+        helpHtml("intro.welcome.practice"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: words }
+      );
     }
-    function displayValue(tval) {
-      tval = tval || "";
-      if (field.hasTextForStringId("options." + tval)) {
-        return field.t("options." + tval, { default: tval });
-      }
-      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
-        return "";
-      }
-      return tval;
+    function words() {
+      reveal(
+        ".intro-nav-wrap .chapter-welcome",
+        helpHtml("intro.welcome.words"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: chapters }
+      );
     }
-    function renderValue(tval) {
-      tval = tval || "";
-      if (field.hasTextForStringId("options." + tval)) {
-        return field.t.append("options." + tval, { default: tval });
-      }
-      if (field.type === "typeCombo" && tval.toLowerCase() === "yes") {
-        tval = "";
-      }
-      return (selection2) => selection2.text(tval);
+    function chapters() {
+      dispatch14.call("done");
+      reveal(
+        ".intro-nav-wrap .chapter-navigation",
+        helpHtml("intro.welcome.chapters", { next: _t("intro.navigation.title") })
+      );
     }
-    function objectDifference(a, b) {
-      return a.filter(function(d1) {
-        return !b.some(function(d2) {
-          return !d2.isMixed && d1.value === d2.value;
-        });
-      });
+    chapter.enter = function() {
+      welcome();
+    };
+    chapter.exit = function() {
+      context.container().select(".curtain-tooltip.intro-mouse").selectAll(".counter").remove();
+    };
+    chapter.restart = function() {
+      chapter.exit();
+      chapter.enter();
+    };
+    return utilRebind(chapter, dispatch14, "on");
+  }
+
+  // modules/ui/intro/navigation.js
+  function uiIntroNavigation(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var timeouts = [];
+    var hallId = "n2061";
+    var townHall = [-85.63591, 41.94285];
+    var springStreetId = "w397";
+    var springStreetEndId = "n1834";
+    var springStreet = [-85.63582, 41.94255];
+    var onewayField = _mainPresetIndex.field("oneway");
+    var maxspeedField = _mainPresetIndex.field("maxspeed");
+    var chapter = {
+      title: "intro.navigation.title"
+    };
+    function timeout2(f2, t2) {
+      timeouts.push(window.setTimeout(f2, t2));
     }
-    function initCombo(selection2, attachTo) {
-      if (!_allowCustomValues) {
-        selection2.attr("readonly", "readonly");
-      }
-      if (_showTagInfoSuggestions && services.taginfo) {
-        selection2.call(_combobox.fetcher(setTaginfoValues), attachTo);
-        setTaginfoValues("", setPlaceholder);
-      } else {
-        selection2.call(_combobox, attachTo);
-        setStaticValues(setPlaceholder);
-      }
+    function eventCancel(d3_event) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
     }
-    function setStaticValues(callback) {
-      if (!_optarray)
-        return;
-      _comboData = _optarray.map(function(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"
-        };
-      });
-      _combobox.data(objectDifference(_comboData, _multiData));
-      if (callback)
-        callback(_comboData);
+    function isTownHallSelected() {
+      var ids = context.selectedIDs();
+      return ids.length === 1 && ids[0] === hallId;
     }
-    function setTaginfoValues(q, callback) {
-      var fn = _isMulti ? "multikeys" : "values";
-      var query = (_isMulti ? field.key : "") + q;
-      var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
-      if (hasCountryPrefix) {
-        query = _countryCode + ":";
+    function dragMap() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var msec = transitionTime(townHall, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
       }
-      var params = {
-        debounce: q !== "",
-        key: field.key,
-        query
-      };
-      if (_entityIDs.length) {
-        params.geometry = context.graph().geometry(_entityIDs[0]);
-      }
-      services.taginfo[fn](params, function(err, data) {
-        if (err)
-          return;
-        data = data.filter(function(d) {
-          return field.type !== "typeCombo" || d.value !== "yes";
+      context.map().centerZoomEase(townHall, 19, msec);
+      timeout2(function() {
+        var centerStart = context.map().center();
+        var textId = context.lastPointerType() === "mouse" ? "drag" : "drag_touch";
+        var dragString = helpHtml("intro.navigation.map_info") + "{br}" + helpHtml("intro.navigation." + textId);
+        reveal(".surface", dragString);
+        context.map().on("drawn.intro", function() {
+          reveal(".surface", dragString, { duration: 0 });
         });
-        var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
-        if (deprecatedValues) {
-          data = data.filter(function(d) {
-            return deprecatedValues.indexOf(d.value) === -1;
-          });
-        }
-        if (hasCountryPrefix) {
-          data = data.filter(function(d) {
-            return d.value.toLowerCase().indexOf(_countryCode + ":") === 0;
-          });
-        }
-        _container.classed("empty-combobox", data.length === 0);
-        _comboData = data.map(function(d) {
-          var k = d.value;
-          if (_isMulti)
-            k = k.replace(field.key, "");
-          var label = field.t("options." + k, { default: k });
-          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"
-          };
+        context.map().on("move.intro", function() {
+          var centerNow = context.map().center();
+          if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
+            context.map().on("move.intro", null);
+            timeout2(function() {
+              continueTo(zoomMap);
+            }, 3e3);
+          }
         });
-        _comboData = objectDifference(_comboData, _multiData);
-        if (callback)
-          callback(_comboData);
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
+      }
+    }
+    function zoomMap() {
+      var zoomStart = context.map().zoom();
+      var textId = context.lastPointerType() === "mouse" ? "zoom" : "zoom_touch";
+      var zoomString = helpHtml("intro.navigation." + textId);
+      reveal(".surface", zoomString);
+      context.map().on("drawn.intro", function() {
+        reveal(".surface", zoomString, { duration: 0 });
+      });
+      context.map().on("move.intro", function() {
+        if (context.map().zoom() !== zoomStart) {
+          context.map().on("move.intro", null);
+          timeout2(function() {
+            continueTo(features);
+          }, 3e3);
+        }
       });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
+      }
     }
-    function setPlaceholder(values) {
-      if (_isMulti || _isSemi) {
-        _staticPlaceholder = field.placeholder() || _t("inspector.add");
-      } else {
-        var vals = values.map(function(d) {
-          return d.value;
-        }).filter(function(s) {
-          return s.length < 20;
-        });
-        var placeholders = vals.length > 1 ? vals : values.map(function(d) {
-          return d.key;
-        });
-        _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(", ");
+    function features() {
+      var onClick = function() {
+        continueTo(pointsLinesAreas);
+      };
+      reveal(
+        ".surface",
+        helpHtml("intro.navigation.features"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("drawn.intro", function() {
+        reveal(
+          ".surface",
+          helpHtml("intro.navigation.features"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+        );
+      });
+      function continueTo(nextStep) {
+        context.map().on("drawn.intro", null);
+        nextStep();
       }
-      if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
-        _staticPlaceholder += "\u2026";
+    }
+    function pointsLinesAreas() {
+      var onClick = function() {
+        continueTo(nodesWays);
+      };
+      reveal(
+        ".surface",
+        helpHtml("intro.navigation.points_lines_areas"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("drawn.intro", function() {
+        reveal(
+          ".surface",
+          helpHtml("intro.navigation.points_lines_areas"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+        );
+      });
+      function continueTo(nextStep) {
+        context.map().on("drawn.intro", null);
+        nextStep();
       }
-      var ph;
-      if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
-        ph = _t("inspector.multiple_values");
-      } else {
-        ph = _staticPlaceholder;
+    }
+    function nodesWays() {
+      var onClick = function() {
+        continueTo(clickTownHall);
+      };
+      reveal(
+        ".surface",
+        helpHtml("intro.navigation.nodes_ways"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("drawn.intro", function() {
+        reveal(
+          ".surface",
+          helpHtml("intro.navigation.nodes_ways"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+        );
+      });
+      function continueTo(nextStep) {
+        context.map().on("drawn.intro", null);
+        nextStep();
       }
-      _container.selectAll("input").attr("placeholder", ph);
     }
-    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);
-        if (!vals.length)
-          return;
-        if (_isMulti) {
-          utilArrayUniq(vals).forEach(function(v) {
-            var key = (field.key || "") + v;
-            if (_tags) {
-              var old = _tags[key];
-              if (typeof old === "string" && old.toLowerCase() !== "no")
-                return;
-            }
-            key = context.cleanTagKey(key);
-            field.keys.push(key);
-            t[key] = "yes";
-          });
-        } else if (_isSemi) {
-          var arr = _multiData.map(function(d) {
-            return d.key;
-          });
-          arr = arr.concat(vals);
-          t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(";"));
+    function clickTownHall() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var entity = context.hasEntity(hallId);
+      if (!entity) return;
+      reveal(null, null, { duration: 0 });
+      context.map().centerZoomEase(entity.loc, 19, 500);
+      timeout2(function() {
+        var entity2 = context.hasEntity(hallId);
+        if (!entity2) return;
+        var box = pointBox(entity2.loc, context);
+        var textId = context.lastPointerType() === "mouse" ? "click_townhall" : "tap_townhall";
+        reveal(box, helpHtml("intro.navigation." + textId));
+        context.map().on("move.intro drawn.intro", function() {
+          var entity3 = context.hasEntity(hallId);
+          if (!entity3) return;
+          var box2 = pointBox(entity3.loc, context);
+          reveal(box2, helpHtml("intro.navigation." + textId), { duration: 0 });
+        });
+        context.on("enter.intro", function() {
+          if (isTownHallSelected()) continueTo(selectedTownHall);
+        });
+      }, 550);
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
         }
-        window.setTimeout(function() {
-          _input.node().focus();
-        }, 10);
-      } else {
-        var rawValue = utilGetSetValue(_input);
-        if (!rawValue && Array.isArray(_tags[field.key]))
-          return;
-        val = context.cleanTagValue(tagValue(rawValue));
-        t[field.key] = val || void 0;
+      });
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-      dispatch10.call("change", this, t);
     }
-    function removeMultikey(d3_event, d) {
-      d3_event.preventDefault();
-      d3_event.stopPropagation();
-      var t = {};
-      if (_isMulti) {
-        t[d.key] = void 0;
-      } else if (_isSemi) {
-        var arr = _multiData.map(function(md) {
-          return md.key === d.key ? null : md.key;
-        }).filter(Boolean);
-        arr = utilArrayUniq(arr);
-        t[field.key] = arr.length ? arr.join(";") : void 0;
+    function selectedTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      var entity = context.hasEntity(hallId);
+      if (!entity) return clickTownHall();
+      var box = pointBox(entity.loc, context);
+      var onClick = function() {
+        continueTo(editorTownHall);
+      };
+      reveal(
+        box,
+        helpHtml("intro.navigation.selected_townhall"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("move.intro drawn.intro", function() {
+        var entity2 = context.hasEntity(hallId);
+        if (!entity2) return;
+        var box2 = pointBox(entity2.loc, context);
+        reveal(
+          box2,
+          helpHtml("intro.navigation.selected_townhall"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+        );
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-      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);
-      if (_isMulti || _isSemi) {
-        _container = _container.selectAll(".chiplist").data([0]);
-        var listClass = "chiplist";
-        if (field.key === "destination" || field.key === "via") {
-          listClass += " full-line-chips";
+    function editorTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      var onClick = function() {
+        continueTo(presetTownHall);
+      };
+      reveal(
+        ".entity-editor-pane",
+        helpHtml("intro.navigation.editor_townhall"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.on("exit.intro", function() {
+        continueTo(clickTownHall);
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
         }
-        _container = _container.enter().append("ul").attr("class", listClass).on("click", function() {
-          window.setTimeout(function() {
-            _input.node().focus();
-          }, 10);
-        }).merge(_container);
-        _inputWrap = _container.selectAll(".input-wrap").data([0]);
-        _inputWrap = _inputWrap.enter().append("li").attr("class", "input-wrap").merge(_inputWrap);
-        _input = _inputWrap.selectAll("input").data([0]);
-      } else {
-        _input = _container.selectAll("input").data([0]);
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        nextStep();
       }
-      _input = _input.enter().append("input").attr("type", "text").attr("id", field.domId).call(utilNoAuto).call(initCombo, selection2).merge(_input);
-      if (_isNetwork) {
-        var extent = combinedEntityExtent();
-        var countryCode = extent && iso1A2Code(extent.center());
-        _countryCode = countryCode && countryCode.toLowerCase();
+    }
+    function presetTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      var entity = context.entity(context.selectedIDs()[0]);
+      var preset = _mainPresetIndex.match(entity, context.graph());
+      var onClick = function() {
+        continueTo(fieldsTownHall);
+      };
+      reveal(
+        ".entity-editor-pane .section-feature-type",
+        helpHtml("intro.navigation.preset_townhall", { preset: preset.name() }),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.on("exit.intro", function() {
+        continueTo(clickTownHall);
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
+        }
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        nextStep();
       }
-      _input.on("change", change).on("blur", change);
-      _input.on("keydown.field", function(d3_event) {
-        switch (d3_event.keyCode) {
-          case 13:
-            _input.node().blur();
-            d3_event.stopPropagation();
-            break;
+    }
+    function fieldsTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      var onClick = function() {
+        continueTo(closeTownHall);
+      };
+      reveal(
+        ".entity-editor-pane .section-preset-fields",
+        helpHtml("intro.navigation.fields_townhall"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.on("exit.intro", function() {
+        continueTo(clickTownHall);
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(hallId)) {
+          continueTo(clickTownHall);
         }
       });
-      if (_isMulti || _isSemi) {
-        _combobox.on("accept", function() {
-          _input.node().blur();
-          _input.node().focus();
-        });
-        _input.on("focus", function() {
-          _container.classed("active", true);
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        nextStep();
+      }
+    }
+    function closeTownHall() {
+      if (!isTownHallSelected()) return clickTownHall();
+      var selector = ".entity-editor-pane button.close svg use";
+      var href = select_default2(selector).attr("href") || "#iD-icon-close";
+      reveal(
+        ".entity-editor-pane",
+        helpHtml("intro.navigation.close_townhall", { button: { html: icon(href, "inline") } })
+      );
+      context.on("exit.intro", function() {
+        continueTo(searchStreet);
+      });
+      context.history().on("change.intro", function() {
+        var selector2 = ".entity-editor-pane button.close svg use";
+        var href2 = select_default2(selector2).attr("href") || "#iD-icon-close";
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.navigation.close_townhall", { button: { html: icon(href2, "inline") } }),
+          { duration: 0 }
+        );
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
+    }
+    function searchStreet() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var msec = transitionTime(springStreet, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
+      }
+      context.map().centerZoomEase(springStreet, 19, msec);
+      timeout2(function() {
+        reveal(
+          ".search-header input",
+          helpHtml("intro.navigation.search_street", { name: _t("intro.graph.name.spring-street") })
+        );
+        context.container().select(".search-header input").on("keyup.intro", checkSearchResult);
+      }, msec + 100);
+    }
+    function checkSearchResult() {
+      var first = context.container().select(".feature-list-item:nth-child(0n+2)");
+      var firstName = first.select(".entity-name");
+      var name = _t("intro.graph.name.spring-street");
+      if (!firstName.empty() && firstName.html() === name) {
+        reveal(
+          first.node(),
+          helpHtml("intro.navigation.choose_street", { name }),
+          { duration: 300 }
+        );
+        context.on("exit.intro", function() {
+          continueTo(selectedStreet);
         });
+        context.container().select(".search-header input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
+      }
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.container().select(".search-header input").on("keydown.intro", null).on("keyup.intro", null);
+        nextStep();
       }
     }
-    combo.tags = function(tags) {
-      _tags = tags;
-      if (_isMulti || _isSemi) {
-        _multiData = [];
-        var maxLength;
-        if (_isMulti) {
-          for (var k in tags) {
-            if (field.key && k.indexOf(field.key) !== 0)
-              continue;
-            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),
-              isMixed: Array.isArray(v)
-            });
-          }
-          if (field.key) {
-            field.keys = _multiData.map(function(d) {
-              return d.key;
-            });
-            maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
-          } else {
-            maxLength = context.maxCharsForTagKey();
-          }
-        } else if (_isSemi) {
-          var allValues = [];
-          var commonValues;
-          if (Array.isArray(tags[field.key])) {
-            tags[field.key].forEach(function(tagVal) {
-              var thisVals = utilArrayUniq((tagVal || "").split(";")).filter(Boolean);
-              allValues = allValues.concat(thisVals);
-              if (!commonValues) {
-                commonValues = thisVals;
-              } else {
-                commonValues = commonValues.filter((value) => thisVals.includes(value));
-              }
-            });
-            allValues = utilArrayUniq(allValues).filter(Boolean);
-          } else {
-            allValues = utilArrayUniq((tags[field.key] || "").split(";")).filter(Boolean);
-            commonValues = allValues;
-          }
-          _multiData = allValues.map(function(v2) {
-            return {
-              key: v2,
-              value: displayValue(v2),
-              display: renderValue(v2),
-              isMixed: !commonValues.includes(v2)
-            };
-          });
-          var currLength = utilUnicodeCharsCount(commonValues.join(";"));
-          maxLength = context.maxCharsForTagValue() - currLength;
-          if (currLength > 0) {
-            maxLength -= 1;
-          }
-        }
-        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;
-        _container.selectAll(".chiplist .input-wrap").style("display", hideAdd ? "none" : null);
-        var chips = _container.selectAll(".chip").data(_multiData);
-        chips.exit().remove();
-        var enter = chips.enter().insert("li", ".input-wrap").attr("class", "chip");
-        enter.append("span");
-        enter.append("a");
-        chips = chips.merge(enter).order().classed("raw-value", function(d) {
-          var k2 = d.key;
-          if (_isMulti)
-            k2 = k2.replace(field.key, "");
-          return !field.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;
+    function selectedStreet() {
+      if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
+        return searchStreet();
+      }
+      var onClick = function() {
+        continueTo(editorStreet);
+      };
+      var entity = context.entity(springStreetEndId);
+      var box = pointBox(entity.loc, context);
+      box.height = 500;
+      reveal(
+        box,
+        helpHtml("intro.navigation.selected_street", { name: _t("intro.graph.name.spring-street") }),
+        { duration: 600, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      timeout2(function() {
+        context.map().on("move.intro drawn.intro", function() {
+          var entity2 = context.hasEntity(springStreetEndId);
+          if (!entity2) return;
+          var box2 = pointBox(entity2.loc, context);
+          box2.height = 500;
+          reveal(
+            box2,
+            helpHtml("intro.navigation.selected_street", { name: _t("intro.graph.name.spring-street") }),
+            { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+          );
         });
-        if (allowDragAndDrop) {
-          registerDragAndDrop(chips);
+      }, 600);
+      context.on("enter.intro", function(mode) {
+        if (!context.hasEntity(springStreetId)) {
+          return continueTo(searchStreet);
         }
-        chips.select("span").each(function(d) {
-          const selection2 = select_default2(this);
-          if (d.display) {
-            selection2.text("");
-            d.display(selection2);
-          } else {
-            selection2.text(d.value);
-          }
-        });
-        chips.select("a").attr("href", "#").on("click", removeMultikey).attr("class", "remove").text("\xD7");
-      } 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"])) {
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            var t = {};
-            t[field.key] = void 0;
-            dispatch10.call("change", this, t);
-          }
-        });
+        var ids = context.selectedIDs();
+        if (mode.id !== "select" || !ids.length || ids[0] !== springStreetId) {
+          context.enter(modeSelect(context, [springStreetId]));
+        }
+      });
+      context.history().on("change.intro", function() {
+        if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
+          timeout2(function() {
+            continueTo(searchStreet);
+          }, 300);
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-    };
-    function registerDragAndDrop(selection2) {
-      var dragOrigin, targetIndex;
-      selection2.call(
-        drag_default().on("start", function(d3_event) {
-          dragOrigin = {
-            x: d3_event.x,
-            y: d3_event.y
-          };
-          targetIndex = null;
-        }).on("drag", function(d3_event) {
-          var 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)
-            return;
-          var index = selection2.nodes().indexOf(this);
-          select_default2(this).classed("dragging", true);
-          targetIndex = null;
-          var targetIndexOffsetTop = null;
-          var draggedTagWidth = select_default2(this).node().offsetWidth;
-          if (field.key === "destination" || field.key === "via") {
-            _container.selectAll(".chip").style("transform", function(d2, index2) {
-              var node = select_default2(this).node();
-              if (index === index2) {
-                return "translate(" + x + "px, " + y + "px)";
-              } else if (index2 > index && d3_event.y > node.offsetTop) {
-                if (targetIndex === null || index2 > targetIndex) {
-                  targetIndex = index2;
-                }
-                return "translateY(-100%)";
-              } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
-                if (targetIndex === null || index2 < targetIndex) {
-                  targetIndex = index2;
-                }
-                return "translateY(100%)";
-              }
-              return null;
-            });
-          } else {
-            _container.selectAll(".chip").each(function(d2, index2) {
-              var node = select_default2(this).node();
-              if (index !== index2 && d3_event.x < node.offsetLeft + node.offsetWidth + 5 && d3_event.x > node.offsetLeft && d3_event.y < node.offsetTop + node.offsetHeight && d3_event.y > node.offsetTop) {
-                targetIndex = index2;
-                targetIndexOffsetTop = node.offsetTop;
-              }
-            }).style("transform", function(d2, index2) {
-              var node = select_default2(this).node();
-              if (index === index2) {
-                return "translate(" + x + "px, " + y + "px)";
-              }
-              if (node.offsetTop === targetIndexOffsetTop) {
-                if (index2 < index && index2 >= targetIndex) {
-                  return "translateX(" + draggedTagWidth + "px)";
-                } else if (index2 > index && index2 <= targetIndex) {
-                  return "translateX(-" + draggedTagWidth + "px)";
-                }
-              }
-              return null;
-            });
-          }
-        }).on("end", function() {
-          if (!select_default2(this).classed("dragging")) {
-            return;
-          }
-          var index = selection2.nodes().indexOf(this);
-          select_default2(this).classed("dragging", false);
-          _container.selectAll(".chip").style("transform", null);
-          if (typeof targetIndex === "number") {
-            var element = _multiData[index];
-            _multiData.splice(index, 1);
-            _multiData.splice(targetIndex, 0, element);
-            var t = {};
-            if (_multiData.length) {
-              t[field.key] = _multiData.map(function(element2) {
-                return element2.key;
-              }).join(";");
-            } else {
-              t[field.key] = void 0;
-            }
-            dispatch10.call("change", this, t);
+    }
+    function editorStreet() {
+      var selector = ".entity-editor-pane button.close svg use";
+      var href = select_default2(selector).attr("href") || "#iD-icon-close";
+      reveal(".entity-editor-pane", helpHtml("intro.navigation.street_different_fields") + "{br}" + helpHtml("intro.navigation.editor_street", {
+        button: { html: icon(href, "inline") },
+        field1: onewayField.title(),
+        field2: maxspeedField.title()
+      }));
+      context.on("exit.intro", function() {
+        continueTo(play);
+      });
+      context.history().on("change.intro", function() {
+        var selector2 = ".entity-editor-pane button.close svg use";
+        var href2 = select_default2(selector2).attr("href") || "#iD-icon-close";
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.navigation.street_different_fields") + "{br}" + helpHtml("intro.navigation.editor_street", {
+            button: { html: icon(href2, "inline") },
+            field1: onewayField.title(),
+            field2: maxspeedField.title()
+          }),
+          { duration: 0 }
+        );
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
+    }
+    function play() {
+      dispatch14.call("done");
+      reveal(
+        ".ideditor",
+        helpHtml("intro.navigation.play", { next: _t("intro.points.title") }),
+        {
+          tooltipBox: ".intro-nav-wrap .chapter-point",
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            reveal(".ideditor");
           }
-          dragOrigin = void 0;
-          targetIndex = void 0;
-        })
+        }
       );
     }
-    combo.focus = function() {
-      _input.node().focus();
+    chapter.enter = function() {
+      dragMap();
     };
-    combo.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return combo;
+    chapter.exit = function() {
+      timeouts.forEach(window.clearTimeout);
+      context.on("enter.intro exit.intro", null);
+      context.map().on("move.intro drawn.intro", null);
+      context.history().on("change.intro", null);
+      context.container().select(".inspector-wrap").on("wheel.intro", null);
+      context.container().select(".search-header input").on("keydown.intro keyup.intro", null);
     };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    return utilRebind(combo, dispatch10, "on");
+    chapter.restart = function() {
+      chapter.exit();
+      chapter.enter();
+    };
+    return utilRebind(chapter, dispatch14, "on");
   }
 
-  // modules/ui/fields/input.js
-  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 _entityIDs = [];
-    var _tags;
-    var _phoneFormats = {};
-    if (field.type === "tel") {
-      _mainFileFetcher.get("phone_formats").then(function(d) {
-        _phoneFormats = d;
-        updatePhonePlaceholder();
-      }).catch(function() {
-      });
+  // modules/ui/intro/point.js
+  function uiIntroPoint(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var timeouts = [];
+    var intersection2 = [-85.63279, 41.94394];
+    var building = [-85.632422, 41.944045];
+    var cafePreset = _mainPresetIndex.item("amenity/cafe");
+    var _pointID = null;
+    var chapter = {
+      title: "intro.points.title"
+    };
+    function timeout2(f2, t2) {
+      timeouts.push(window.setTimeout(f2, t2));
     }
-    function calcLocked() {
-      var isLocked = (field.id === "brand" || field.id === "network" || field.id === "operator" || field.id === "flag") && _entityIDs.length && _entityIDs.some(function(entityID) {
-        var entity = context.graph().hasEntity(entityID);
-        if (!entity)
-          return false;
-        if (entity.tags.wikidata)
-          return true;
-        var preset = _mainPresetIndex.match(entity, context.graph());
-        var isSuggestion = preset && preset.suggestion;
-        var which = field.id;
-        return isSuggestion && !!entity.tags[which] && !!entity.tags[which + ":wikidata"];
-      });
-      field.locked(isLocked);
+    function eventCancel(d3_event) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
     }
-    function i2(selection2) {
-      calcLocked();
-      var isLocked = field.locked();
-      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      input = wrap2.selectAll("input").data([0]);
-      input = input.enter().append("input").attr("type", field.type === "identifier" ? "text" : field.type).attr("id", field.domId).classed(field.type, true).call(utilNoAuto).merge(input);
-      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
-      if (field.type === "tel") {
-        updatePhonePlaceholder();
-      } else if (field.type === "number") {
-        var rtl = _mainLocalizer.textDirection() === "rtl";
-        input.attr("type", "text");
-        var inc = field.increment;
-        var buttons = wrap2.selectAll(".increment, .decrement").data(rtl ? [inc, -inc] : [-inc, inc]);
-        buttons.enter().append("button").attr("class", function(d) {
-          var which = d > 0 ? "increment" : "decrement";
-          return "form-field-button " + which;
-        }).attr("title", function(d) {
-          var which = d > 0 ? "increment" : "decrement";
-          return _t(`inspector.${which}`);
-        }).merge(buttons).on("click", function(d3_event, d) {
-          d3_event.preventDefault();
-          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();
-          });
-          input.node().value = vals.join(";");
-          change()();
+    function addPoint() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var msec = transitionTime(intersection2, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
+      }
+      context.map().centerZoomEase(intersection2, 19, msec);
+      timeout2(function() {
+        var tooltip = reveal(
+          "button.add-point",
+          helpHtml("intro.points.points_info") + "{br}" + helpHtml("intro.points.add_point")
+        );
+        _pointID = null;
+        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-points");
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "add-point") return;
+          continueTo(placePoint);
         });
-      } else if (field.type === "identifier" && field.urlFormat && field.pattern) {
-        input.attr("type", "text");
-        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
-        outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", function() {
-          var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
-          if (domainResults.length >= 2 && domainResults[1]) {
-            var domain2 = domainResults[1];
-            return _t("icons.view_on", { domain: domain2 });
-          }
-          return "";
-        }).on("click", function(d3_event) {
-          d3_event.preventDefault();
-          var value = validIdentifierValueForLink();
-          if (value) {
-            var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
-            window.open(url, "_blank");
-          }
-        }).merge(outlinkButton);
-      } else if (field.type === "url") {
-        input.attr("type", "text");
-        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
-        outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", () => _t("icons.visit_website")).on("click", function(d3_event) {
-          d3_event.preventDefault();
-          const value = validIdentifierValueForLink();
-          if (value)
-            window.open(value, "_blank");
-        }).merge(outlinkButton);
-      } else if (field.key.split(":").includes("colour")) {
-        input.attr("type", "text");
-        updateColourPreview();
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        nextStep();
       }
     }
-    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;
+    function placePoint() {
+      if (context.mode().id !== "add-point") {
+        return chapter.restart();
       }
-      return true;
-    }
-    function updateColourPreview() {
-      wrap2.selectAll(".colour-preview").remove();
-      const colour = utilGetSetValue(input);
-      if (!isColourValid(colour) && colour !== "")
-        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) {
-        d3_event.preventDefault();
-        var colour2 = this.value;
-        if (!isColourValid(colour2))
-          return;
-        utilGetSetValue(input, this.value);
-        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");
-      if (colour === "") {
-        outlinkButton = outlinkButton.call(svgIcon("#iD-icon-edit"));
+      var pointBox2 = pad(building, 150, context);
+      var textId = context.lastPointerType() === "mouse" ? "place_point" : "place_point_touch";
+      reveal(pointBox2, helpHtml("intro.points." + textId));
+      context.map().on("move.intro drawn.intro", function() {
+        pointBox2 = pad(building, 150, context);
+        reveal(pointBox2, helpHtml("intro.points." + textId), { duration: 0 });
+      });
+      context.on("enter.intro", function(mode) {
+        if (mode.id !== "select") return chapter.restart();
+        _pointID = context.mode().selectedIDs()[0];
+        if (context.graph().geometry(_pointID) === "vertex") {
+          context.map().on("move.intro drawn.intro", null);
+          context.on("enter.intro", null);
+          reveal(pointBox2, helpHtml("intro.points.place_point_error"), {
+            buttonText: _t.html("intro.ok"),
+            buttonCallback: function() {
+              return chapter.restart();
+            }
+          });
+        } else {
+          continueTo(searchPreset);
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-      outlinkButton.on("click", () => wrap2.select(".colour-selector").node().click()).merge(outlinkButton);
-    }
-    function updatePhonePlaceholder() {
-      if (input.empty() || !Object.keys(_phoneFormats).length)
-        return;
-      var extent = combinedEntityExtent();
-      var countryCode = extent && iso1A2Code(extent.center());
-      var format2 = countryCode && _phoneFormats[countryCode.toLowerCase()];
-      if (format2)
-        input.attr("placeholder", format2);
     }
-    function validIdentifierValueForLink() {
-      const value = utilGetSetValue(input).trim();
-      if (field.type === "url" && value) {
-        try {
-          return new URL(value).href;
-        } catch (e) {
-          return null;
+    function searchPreset() {
+      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
+        return addPoint();
+      }
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
+      reveal(
+        ".preset-search-input",
+        helpHtml("intro.points.search_cafe", { preset: cafePreset.name() })
+      );
+      context.on("enter.intro", function(mode) {
+        if (!_pointID || !context.hasEntity(_pointID)) {
+          return continueTo(addPoint);
+        }
+        var ids = context.selectedIDs();
+        if (mode.id !== "select" || !ids.length || ids[0] !== _pointID) {
+          context.enter(modeSelect(context, [_pointID]));
+          context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+          context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
+          reveal(
+            ".preset-search-input",
+            helpHtml("intro.points.search_cafe", { preset: cafePreset.name() })
+          );
+          context.history().on("change.intro", null);
+        }
+      });
+      function checkPresetSearch() {
+        var first = context.container().select(".preset-list-item:first-child");
+        if (first.classed("preset-amenity-cafe")) {
+          context.container().select(".preset-search-input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
+          reveal(
+            first.select(".preset-list-button").node(),
+            helpHtml("intro.points.choose_cafe", { preset: cafePreset.name() }),
+            { duration: 300 }
+          );
+          context.history().on("change.intro", function() {
+            continueTo(aboutFeatureEditor);
+          });
         }
       }
-      if (field.type === "identifier" && field.pattern) {
-        return value && value.match(new RegExp(field.pattern))[0];
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
+        nextStep();
       }
-      return null;
     }
-    function clamped(num) {
-      if (field.minValue !== void 0) {
-        num = Math.max(num, field.minValue);
+    function aboutFeatureEditor() {
+      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
+        return addPoint();
       }
-      if (field.maxValue !== void 0) {
-        num = Math.min(num, field.maxValue);
+      timeout2(function() {
+        reveal(".entity-editor-pane", helpHtml("intro.points.feature_editor"), {
+          tooltipClass: "intro-points-describe",
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            continueTo(addName);
+          }
+        });
+      }, 400);
+      context.on("exit.intro", function() {
+        continueTo(reselectPoint);
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
       }
-      return num;
     }
-    function change(onInput) {
-      return function() {
-        var t = {};
-        var val = utilGetSetValue(input);
-        if (!onInput)
-          val = context.cleanTagValue(val);
-        if (!val && Array.isArray(_tags[field.key]))
-          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);
+    function addName() {
+      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
+        return addPoint();
+      }
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      var addNameString = helpHtml("intro.points.fields_info") + "{br}" + helpHtml("intro.points.add_name");
+      timeout2(function() {
+        var entity = context.entity(_pointID);
+        if (entity.tags.name) {
+          var tooltip = reveal(".entity-editor-pane", addNameString, {
+            tooltipClass: "intro-points-describe",
+            buttonText: _t.html("intro.ok"),
+            buttonCallback: function() {
+              continueTo(addCloseEditor);
+            }
+          });
+          tooltip.select(".instruction").style("display", "none");
+        } else {
+          reveal(
+            ".entity-editor-pane",
+            addNameString,
+            { tooltipClass: "intro-points-describe" }
+          );
         }
-        t[field.key] = val || void 0;
-        dispatch10.call("change", this, t, onInput);
-      };
-    }
-    i2.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return i2;
-    };
-    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"))
-        updateColourPreview();
-      if (outlinkButton && !outlinkButton.empty()) {
-        var disabled = !validIdentifierValueForLink();
-        outlinkButton.classed("disabled", disabled);
+      }, 400);
+      context.history().on("change.intro", function() {
+        continueTo(addCloseEditor);
+      });
+      context.on("exit.intro", function() {
+        continueTo(reselectPoint);
+      });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-    };
-    i2.focus = function() {
-      var node = input.node();
-      if (node)
-        node.focus();
-    };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
     }
-    return utilRebind(i2, dispatch10, "on");
-  }
-
-  // modules/ui/fields/access.js
-  function uiFieldAccess(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var items = select_default2(null);
-    var _tags;
-    function access(selection2) {
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var list = wrap2.selectAll("ul").data([0]);
-      list = list.enter().append("ul").attr("class", "rows").merge(list);
-      items = list.selectAll("li").data(field.keys);
-      var enter = items.enter().append("li").attr("class", function(d) {
-        return "labeled-input preset-access-" + d;
-      });
-      enter.append("span").attr("class", "label preset-label-access").attr("for", function(d) {
-        return "preset-input-access-" + d;
-      }).html(function(d) {
-        return field.t.html("types." + d);
-      });
-      enter.append("div").attr("class", "preset-input-access-wrap").append("input").attr("type", "text").attr("class", function(d) {
-        return "preset-input-access preset-input-access-" + d;
-      }).call(utilNoAuto).each(function(d) {
-        select_default2(this).call(
-          uiCombobox(context, "access-" + d).data(access.options(d))
-        );
+    function addCloseEditor() {
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      var selector = ".entity-editor-pane button.close svg use";
+      var href = select_default2(selector).attr("href") || "#iD-icon-close";
+      context.on("exit.intro", function() {
+        continueTo(reselectPoint);
       });
-      items = items.merge(enter);
-      wrap2.selectAll(".preset-input-access").on("change", change).on("blur", change);
+      reveal(
+        ".entity-editor-pane",
+        helpHtml("intro.points.add_close", { button: { html: icon(href, "inline") } })
+      );
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
+      }
     }
-    function change(d3_event, d) {
-      var tag = {};
-      var value = context.cleanTagValue(utilGetSetValue(select_default2(this)));
-      if (!value && typeof _tags[d] !== "string")
-        return;
-      tag[d] = value || void 0;
-      dispatch10.call("change", this, tag);
+    function reselectPoint() {
+      if (!_pointID) return chapter.restart();
+      var entity = context.hasEntity(_pointID);
+      if (!entity) return chapter.restart();
+      var oldPreset = _mainPresetIndex.match(entity, context.graph());
+      context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
+      context.enter(modeBrowse(context));
+      var msec = transitionTime(entity.loc, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
+      }
+      context.map().centerEase(entity.loc, msec);
+      timeout2(function() {
+        var box = pointBox(entity.loc, context);
+        reveal(box, helpHtml("intro.points.reselect"), { duration: 600 });
+        timeout2(function() {
+          context.map().on("move.intro drawn.intro", function() {
+            var entity2 = context.hasEntity(_pointID);
+            if (!entity2) return chapter.restart();
+            var box2 = pointBox(entity2.loc, context);
+            reveal(box2, helpHtml("intro.points.reselect"), { duration: 0 });
+          });
+        }, 600);
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "select") return;
+          continueTo(updatePoint);
+        });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
+      }
     }
-    access.options = function(type3) {
-      var options2 = [
-        "yes",
-        "no",
-        "designated",
-        "permissive",
-        "destination",
-        "customers",
-        "private",
-        "permit",
-        "unknown"
-      ];
-      if (type3 === "access") {
-        options2 = options2.filter((v) => v !== "yes" && v !== "designated");
+    function updatePoint() {
+      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
+        return continueTo(reselectPoint);
       }
-      if (type3 === "bicycle") {
-        options2.splice(options2.length - 4, 0, "dismount");
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      context.on("exit.intro", function() {
+        continueTo(reselectPoint);
+      });
+      context.history().on("change.intro", function() {
+        continueTo(updateCloseEditor);
+      });
+      timeout2(function() {
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.points.update"),
+          { tooltipClass: "intro-points-describe" }
+        );
+      }, 400);
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-      return options2.map(function(option) {
-        return {
-          title: field.t("options." + option + ".description"),
-          value: option
-        };
+    }
+    function updateCloseEditor() {
+      if (context.mode().id !== "select" || !_pointID || !context.hasEntity(_pointID)) {
+        return continueTo(reselectPoint);
+      }
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      context.on("exit.intro", function() {
+        continueTo(rightClickPoint);
       });
-    };
-    const placeholdersByTag = {
-      highway: {
-        footway: {
-          foot: "designated",
-          motor_vehicle: "no"
-        },
-        steps: {
-          foot: "yes",
-          motor_vehicle: "no",
-          bicycle: "no",
-          horse: "no"
-        },
-        pedestrian: {
-          foot: "yes",
-          motor_vehicle: "no"
-        },
-        cycleway: {
-          motor_vehicle: "no",
-          bicycle: "designated"
-        },
-        bridleway: {
-          motor_vehicle: "no",
-          horse: "designated"
-        },
-        path: {
-          foot: "yes",
-          motor_vehicle: "no",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        motorway: {
-          foot: "no",
-          motor_vehicle: "yes",
-          bicycle: "no",
-          horse: "no"
-        },
-        trunk: {
-          motor_vehicle: "yes"
-        },
-        primary: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        secondary: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        tertiary: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        residential: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        unclassified: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        service: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        motorway_link: {
-          foot: "no",
-          motor_vehicle: "yes",
-          bicycle: "no",
-          horse: "no"
-        },
-        trunk_link: {
-          motor_vehicle: "yes"
-        },
-        primary_link: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        secondary_link: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        tertiary_link: {
-          foot: "yes",
-          motor_vehicle: "yes",
-          bicycle: "yes",
-          horse: "yes"
-        },
-        construction: {
-          access: "no"
-        }
-      },
-      barrier: {
-        bollard: {
-          access: "no",
-          bicycle: "yes",
-          foot: "yes"
-        },
-        bus_trap: {
-          motor_vehicle: "no",
-          psv: "yes",
-          foot: "yes",
-          bicycle: "yes"
-        },
-        city_wall: {
-          access: "no"
-        },
-        coupure: {
-          access: "yes"
-        },
-        cycle_barrier: {
-          motor_vehicle: "no"
-        },
-        ditch: {
-          access: "no"
-        },
-        entrance: {
-          access: "yes"
-        },
-        fence: {
-          access: "no"
-        },
-        hedge: {
-          access: "no"
-        },
-        jersey_barrier: {
-          access: "no"
-        },
-        motorcycle_barrier: {
-          motor_vehicle: "no"
-        },
-        rail_guard: {
-          access: "no"
-        }
-      }
-    };
-    access.tags = function(tags) {
-      _tags = tags;
-      utilGetSetValue(items.selectAll(".preset-input-access"), function(d) {
-        return typeof tags[d] === "string" ? tags[d] : "";
-      }).classed("mixed", function(d) {
-        return tags[d] && Array.isArray(tags[d]);
-      }).attr("title", function(d) {
-        return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join("\n");
-      }).attr("placeholder", function(d) {
-        if (tags[d] && Array.isArray(tags[d])) {
-          return _t("inspector.multiple_values");
-        }
-        if (d === "bicycle" || d === "motor_vehicle") {
-          if (tags.vehicle && typeof tags.vehicle === "string") {
-            return tags.vehicle;
-          }
-        }
-        if (tags.access && typeof tags.access === "string") {
-          return tags.access;
-        }
-        function getPlaceholdersByTag(key, placeholdersByKey) {
-          if (typeof tags[key] === "string") {
-            if (placeholdersByKey[tags[key]] && placeholdersByKey[tags[key]][d]) {
-              return placeholdersByKey[tags[key]][d];
-            }
-          } else {
-            var impliedAccesses = tags[key].filter(Boolean).map(function(val) {
-              return placeholdersByKey[val] && placeholdersByKey[val][d];
-            }).filter(Boolean);
-            if (impliedAccesses.length === tags[key].length && new Set(impliedAccesses).size === 1) {
-              return impliedAccesses[0];
-            }
-          }
-        }
-        for (const key in placeholdersByTag) {
-          if (tags[key]) {
-            const impliedAccess = getPlaceholdersByTag(key, placeholdersByTag[key]);
-            if (impliedAccess) {
-              return impliedAccess;
-            }
-          }
-        }
-        if (d === "access" && !tags.barrier) {
-          return "yes";
-        }
-        return field.placeholder();
-      });
-    };
-    access.focus = function() {
-      items.selectAll(".preset-input-access").node().focus();
-    };
-    return utilRebind(access, dispatch10, "on");
-  }
-
-  // modules/ui/fields/address.js
-  function uiFieldAddress(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var _selection = select_default2(null);
-    var _wrap = select_default2(null);
-    var addrField = _mainPresetIndex.field("address");
-    var _entityIDs = [];
-    var _tags;
-    var _countryCode;
-    var _addressFormats = [{
-      format: [
-        ["housenumber", "street"],
-        ["city", "postcode"]
-      ]
-    }];
-    _mainFileFetcher.get("address_formats").then(function(d) {
-      _addressFormats = d;
-      if (!_selection.empty()) {
-        _selection.call(address);
-      }
-    }).catch(function() {
-    });
-    function getNearStreets() {
-      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);
-        return {
-          title: d.tags.name,
-          value: d.tags.name,
-          dist: choice.distance
-        };
-      }).sort(function(a, b) {
-        return a.dist - b.dist;
-      });
-      return utilArrayUniqBy(streets, "value");
-      function isAddressable(d) {
-        return d.tags.highway && d.tags.name && d.type === "way";
+      timeout2(function() {
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.points.update_close", { button: { html: icon("#iD-icon-close", "inline") } })
+        );
+      }, 500);
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
       }
     }
-    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;
+    function rightClickPoint() {
+      if (!_pointID) return chapter.restart();
+      var entity = context.hasEntity(_pointID);
+      if (!entity) return chapter.restart();
+      context.enter(modeBrowse(context));
+      var box = pointBox(entity.loc, context);
+      var textId = context.lastPointerType() === "mouse" ? "rightclick" : "edit_menu_touch";
+      reveal(box, helpHtml("intro.points." + textId), { duration: 600 });
+      timeout2(function() {
+        context.map().on("move.intro", function() {
+          var entity2 = context.hasEntity(_pointID);
+          if (!entity2) return chapter.restart();
+          var box2 = pointBox(entity2.loc, context);
+          reveal(box2, helpHtml("intro.points." + textId), { duration: 0 });
+        });
+      }, 600);
+      context.on("enter.intro", function(mode) {
+        if (mode.id !== "select") return;
+        var ids = context.selectedIDs();
+        if (ids.length !== 1 || ids[0] !== _pointID) return;
+        timeout2(function() {
+          var node = selectMenuItem(context, "delete").node();
+          if (!node) return;
+          continueTo(enterDelete);
+        }, 50);
       });
-      return utilArrayUniqBy(cities, "value");
-      function isAddressable(d) {
-        if (d.tags.name) {
-          if (d.tags.admin_level === "8" && d.tags.boundary === "administrative")
-            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"])
-          return true;
-        return false;
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.map().on("move.intro", null);
+        nextStep();
       }
     }
-    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");
-    }
-    function updateForCountryCode() {
-      if (!_countryCode)
-        return;
-      var addressFormat;
-      for (var i2 = 0; i2 < _addressFormats.length; i2++) {
-        var format2 = _addressFormats[i2];
-        if (!format2.countryCodes) {
-          addressFormat = format2;
-        } else if (format2.countryCodes.indexOf(_countryCode) !== -1) {
-          addressFormat = format2;
-          break;
-        }
+    function enterDelete() {
+      if (!_pointID) return chapter.restart();
+      var entity = context.hasEntity(_pointID);
+      if (!entity) return chapter.restart();
+      var node = selectMenuItem(context, "delete").node();
+      if (!node) {
+        return continueTo(rightClickPoint);
       }
-      var dropdowns = addressFormat.dropdowns || [
-        "city",
-        "county",
-        "country",
-        "district",
-        "hamlet",
-        "neighbourhood",
-        "place",
-        "postcode",
-        "province",
-        "quarter",
-        "state",
-        "street",
-        "subdistrict",
-        "suburb"
-      ];
-      var widths = addressFormat.widths || {
-        housenumber: 1 / 3,
-        street: 2 / 3,
-        city: 2 / 3,
-        state: 1 / 4,
-        postcode: 1 / 3
-      };
-      function row(r) {
-        var total = r.reduce(function(sum, key) {
-          return sum + (widths[key] || 0.5);
-        }, 0);
-        return r.map(function(key) {
-          return {
-            id: key,
-            width: (widths[key] || 0.5) / total
-          };
+      reveal(
+        ".edit-menu",
+        helpHtml("intro.points.delete"),
+        { padding: 50 }
+      );
+      timeout2(function() {
+        context.map().on("move.intro", function() {
+          reveal(
+            ".edit-menu",
+            helpHtml("intro.points.delete"),
+            { duration: 0, padding: 50 }
+          );
         });
-      }
-      var rows = _wrap.selectAll(".addr-row").data(addressFormat.format, function(d) {
-        return d.toString();
+      }, 300);
+      context.on("exit.intro", function() {
+        if (!_pointID) return chapter.restart();
+        var entity2 = context.hasEntity(_pointID);
+        if (entity2) return continueTo(rightClickPoint);
       });
-      rows.exit().remove();
-      rows.enter().append("div").attr("class", "addr-row").selectAll("input").data(row).enter().append("input").property("type", "text").call(updatePlaceholder).attr("class", function(d) {
-        return "addr-" + d.id;
-      }).call(utilNoAuto).each(addDropdown).style("width", function(d) {
-        return d.width * 100 + "%";
+      context.history().on("change.intro", function(changed) {
+        if (changed.deleted().length) {
+          continueTo(undo);
+        }
       });
-      function addDropdown(d) {
-        if (dropdowns.indexOf(d.id) === -1)
-          return;
-        var nearValues = d.id === "street" ? getNearStreets : d.id === "city" ? getNearCities : getNearValues;
-        select_default2(this).call(
-          uiCombobox(context, "address-" + d.id).minItems(1).caseSensitive(true).fetcher(function(value, callback) {
-            callback(nearValues("addr:" + d.id));
-          })
-        );
+      function continueTo(nextStep) {
+        context.map().on("move.intro", null);
+        context.history().on("change.intro", null);
+        context.on("exit.intro", null);
+        nextStep();
       }
-      _wrap.selectAll("input").on("blur", change()).on("change", change());
-      _wrap.selectAll("input:not(.combobox-input)").on("input", change(true));
-      if (_tags)
-        updateTags(_tags);
     }
-    function address(selection2) {
-      _selection = selection2;
-      _wrap = selection2.selectAll(".form-field-input-wrap").data([0]);
-      _wrap = _wrap.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(_wrap);
-      var extent = combinedEntityExtent();
-      if (extent) {
-        var countryCode;
-        if (context.inIntro()) {
-          countryCode = _t("intro.graph.countrycode");
-        } else {
-          var center = extent.center();
-          countryCode = iso1A2Code(center);
-        }
-        if (countryCode) {
-          _countryCode = countryCode.toLowerCase();
-          updateForCountryCode();
-        }
+    function undo() {
+      context.history().on("change.intro", function() {
+        continueTo(play);
+      });
+      reveal(
+        ".top-toolbar button.undo-button",
+        helpHtml("intro.points.undo")
+      );
+      function continueTo(nextStep) {
+        context.history().on("change.intro", null);
+        nextStep();
       }
     }
-    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);
-      };
-    }
-    function updatePlaceholder(inputSelection) {
-      return inputSelection.attr("placeholder", function(subfield) {
-        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);
+    function play() {
+      dispatch14.call("done");
+      reveal(
+        ".ideditor",
+        helpHtml("intro.points.play", { next: _t("intro.areas.title") }),
+        {
+          tooltipBox: ".intro-nav-wrap .chapter-area",
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            reveal(".ideditor");
+          }
         }
-      });
-    }
-    function updateTags(tags) {
-      utilGetSetValue(_wrap.selectAll("input"), function(subfield) {
-        var val = tags[field.key + ":" + subfield.id];
-        return typeof val === "string" ? val : "";
-      }).attr("title", function(subfield) {
-        var val = tags[field.key + ":" + subfield.id];
-        return val && Array.isArray(val) ? val.filter(Boolean).join("\n") : void 0;
-      }).classed("mixed", function(subfield) {
-        return Array.isArray(tags[field.key + ":" + subfield.id]);
-      }).call(updatePlaceholder);
-    }
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+      );
     }
-    address.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return address;
+    chapter.enter = function() {
+      addPoint();
     };
-    address.tags = function(tags) {
-      _tags = tags;
-      updateTags(tags);
+    chapter.exit = function() {
+      timeouts.forEach(window.clearTimeout);
+      context.on("enter.intro exit.intro", null);
+      context.map().on("move.intro drawn.intro", null);
+      context.history().on("change.intro", null);
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
     };
-    address.focus = function() {
-      var node = _wrap.selectAll("input").node();
-      if (node)
-        node.focus();
+    chapter.restart = function() {
+      chapter.exit();
+      chapter.enter();
     };
-    return utilRebind(address, dispatch10, "on");
+    return utilRebind(chapter, dispatch14, "on");
   }
 
-  // modules/ui/fields/cycleway.js
-  function uiFieldCycleway(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var items = select_default2(null);
-    var wrap2 = select_default2(null);
-    var _tags;
-    function cycleway(selection2) {
-      function stripcolon(s) {
-        return s.replace(":", "");
+  // modules/ui/intro/area.js
+  function uiIntroArea(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var playground = [-85.63552, 41.94159];
+    var playgroundPreset = _mainPresetIndex.item("leisure/playground");
+    var nameField = _mainPresetIndex.field("name");
+    var descriptionField = _mainPresetIndex.field("description");
+    var timeouts = [];
+    var _areaID;
+    var chapter = {
+      title: "intro.areas.title"
+    };
+    function timeout2(f2, t2) {
+      timeouts.push(window.setTimeout(f2, t2));
+    }
+    function eventCancel(d3_event) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
+    }
+    function revealPlayground(center, text, options2) {
+      var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
+      var box = pad(center, padding, context);
+      reveal(box, text, options2);
+    }
+    function addArea() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      _areaID = null;
+      var msec = transitionTime(playground, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
       }
-      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var div = wrap2.selectAll("ul").data([0]);
-      div = div.enter().append("ul").attr("class", "rows").merge(div);
-      var keys = ["cycleway:left", "cycleway:right"];
-      items = div.selectAll("li").data(keys);
-      var enter = items.enter().append("li").attr("class", function(d) {
-        return "labeled-input preset-cycleway-" + stripcolon(d);
-      });
-      enter.append("span").attr("class", "label preset-label-cycleway").attr("for", function(d) {
-        return "preset-input-cycleway-" + 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))
+      context.map().centerZoomEase(playground, 19, msec);
+      timeout2(function() {
+        var tooltip = reveal(
+          "button.add-area",
+          helpHtml("intro.areas.add_playground")
         );
-      });
-      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;
+        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-areas");
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "add-area") return;
+          continueTo(startPlayground);
+        });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        nextStep();
       }
-      dispatch10.call("change", this, tag);
     }
-    cycleway.options = function() {
-      return field.options.map(function(option) {
-        return {
-          title: field.t("options." + option + ".description"),
-          value: option
-        };
-      });
-    };
-    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");
-        }
-        return field.placeholder();
-      }).classed("mixed", function(d) {
-        return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
-      });
-    };
-    cycleway.focus = function() {
-      var node = wrap2.selectAll("input").node();
-      if (node)
-        node.focus();
-    };
-    return utilRebind(cycleway, dispatch10, "on");
-  }
-
-  // modules/ui/fields/lanes.js
-  function uiFieldLanes(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var LANE_WIDTH = 40;
-    var LANE_HEIGHT = 200;
-    var _entityIDs = [];
-    function lanes(selection2) {
-      var lanesData = context.entity(_entityIDs[0]).lanes();
-      if (!context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode) {
-        selection2.call(lanes.off);
-        return;
+    function startPlayground() {
+      if (context.mode().id !== "add-area") {
+        return chapter.restart();
       }
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var surface = wrap2.selectAll(".surface").data([0]);
-      var d = utilGetDimensions(wrap2);
-      var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
-      surface = surface.enter().append("svg").attr("width", d[0]).attr("height", 300).attr("class", "surface").merge(surface);
-      var lanesSelection = surface.selectAll(".lanes").data([0]);
-      lanesSelection = lanesSelection.enter().append("g").attr("class", "lanes").merge(lanesSelection);
-      lanesSelection.attr("transform", function() {
-        return "translate(" + freeSpace / 2 + ", 0)";
-      });
-      var lane = lanesSelection.selectAll(".lane").data(lanesData.lanes);
-      lane.exit().remove();
-      var enter = lane.enter().append("g").attr("class", "lane");
-      enter.append("g").append("rect").attr("y", 50).attr("width", LANE_WIDTH).attr("height", LANE_HEIGHT);
-      enter.append("g").attr("class", "forward").append("text").attr("y", 40).attr("x", 14).text("\u25B2");
-      enter.append("g").attr("class", "bothways").append("text").attr("y", 40).attr("x", 14).text("\u25B2\u25BC");
-      enter.append("g").attr("class", "backward").append("text").attr("y", 40).attr("x", 14).text("\u25BC");
-      lane = lane.merge(enter);
-      lane.attr("transform", function(d2) {
-        return "translate(" + LANE_WIDTH * d2.index * 1.5 + ", 0)";
-      });
-      lane.select(".forward").style("visibility", function(d2) {
-        return d2.direction === "forward" ? "visible" : "hidden";
-      });
-      lane.select(".bothways").style("visibility", function(d2) {
-        return d2.direction === "bothways" ? "visible" : "hidden";
-      });
-      lane.select(".backward").style("visibility", function(d2) {
-        return d2.direction === "backward" ? "visible" : "hidden";
-      });
-    }
-    lanes.entityIDs = function(val) {
-      _entityIDs = val;
-    };
-    lanes.tags = function() {
-    };
-    lanes.focus = function() {
-    };
-    lanes.off = function() {
-    };
-    return utilRebind(lanes, dispatch10, "on");
-  }
-  uiFieldLanes.supportsMultiselection = false;
-
-  // modules/ui/fields/localized.js
-  var _languagesArray = [];
-  function uiFieldLocalized(field, context) {
-    var dispatch10 = dispatch_default("change", "input");
-    var wikipedia = services.wikipedia;
-    var input = select_default2(null);
-    var localizedInputs = select_default2(null);
-    var _countryCode;
-    var _tags;
-    _mainFileFetcher.get("languages").then(loadLanguagesArray).catch(function() {
-    });
-    var _territoryLanguages = {};
-    _mainFileFetcher.get("territory_languages").then(function(d) {
-      _territoryLanguages = d;
-    }).catch(function() {
-    });
-    var langCombo = uiCombobox(context, "localized-lang").fetcher(fetchLanguages).minItems(0);
-    var _selection = select_default2(null);
-    var _multilingual = [];
-    var _buttonTip = uiTooltip().title(() => _t.append("translate.translate")).placement("left");
-    var _wikiTitles;
-    var _entityIDs = [];
-    function loadLanguagesArray(dataLanguages) {
-      if (_languagesArray.length !== 0)
-        return;
-      var replacements = {
-        sr: "sr-Cyrl",
-        "sr-Cyrl": false
-      };
-      for (var code in dataLanguages) {
-        if (replacements[code] === false)
-          continue;
-        var metaCode = code;
-        if (replacements[code])
-          metaCode = replacements[code];
-        _languagesArray.push({
-          localName: _mainLocalizer.languageName(metaCode, { localOnly: true }),
-          nativeName: dataLanguages[metaCode].nativeName,
-          code,
-          label: _mainLocalizer.languageName(metaCode)
-        });
-      }
-    }
-    function calcLocked() {
-      var isLocked = field.id === "name" && _entityIDs.length && _entityIDs.some(function(entityID) {
-        var entity = context.graph().hasEntity(entityID);
-        if (!entity)
-          return false;
-        if (entity.tags.wikidata)
-          return true;
-        if (entity.tags["name:etymology:wikidata"])
-          return true;
-        var preset = _mainPresetIndex.match(entity, context.graph());
-        if (preset) {
-          var isSuggestion = preset.suggestion;
-          var fields = preset.fields();
-          var showsBrandField = fields.some(function(d) {
-            return d.id === "brand";
+      _areaID = null;
+      context.map().zoomEase(19.5, 500);
+      timeout2(function() {
+        var textId = context.lastPointerType() === "mouse" ? "starting_node_click" : "starting_node_tap";
+        var startDrawString = helpHtml("intro.areas.start_playground") + helpHtml("intro.areas." + textId);
+        revealPlayground(
+          playground,
+          startDrawString,
+          { duration: 250 }
+        );
+        timeout2(function() {
+          context.map().on("move.intro drawn.intro", function() {
+            revealPlayground(
+              playground,
+              startDrawString,
+              { duration: 0 }
+            );
           });
-          var showsOperatorField = fields.some(function(d) {
-            return d.id === "operator";
+          context.on("enter.intro", function(mode) {
+            if (mode.id !== "draw-area") return chapter.restart();
+            continueTo(continuePlayground);
           });
-          var setsName = preset.addTags.name;
-          var setsBrandWikidata = preset.addTags["brand:wikidata"];
-          var setsOperatorWikidata = preset.addTags["operator:wikidata"];
-          return isSuggestion && setsName && (setsBrandWikidata && !showsBrandField || setsOperatorWikidata && !showsOperatorField);
-        }
-        return false;
-      });
-      field.locked(isLocked);
+        }, 250);
+      }, 550);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
+      }
     }
-    function calcMultilingual(tags) {
-      var existingLangsOrdered = _multilingual.map(function(item2) {
-        return item2.lang;
-      });
-      var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
-      for (var k in tags) {
-        var m = k.match(/^(.*):([a-z]{2,3}(?:-[A-Z][a-z]{3})?(?:-[A-Z]{2})?)$/);
-        if (m && m[1] === field.key && m[2]) {
-          var item = { lang: m[2], value: tags[k] };
-          if (existingLangs.has(item.lang)) {
-            _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
-            existingLangs.delete(item.lang);
+    function continuePlayground() {
+      if (context.mode().id !== "draw-area") {
+        return chapter.restart();
+      }
+      _areaID = null;
+      revealPlayground(
+        playground,
+        helpHtml("intro.areas.continue_playground"),
+        { duration: 250 }
+      );
+      timeout2(function() {
+        context.map().on("move.intro drawn.intro", function() {
+          revealPlayground(
+            playground,
+            helpHtml("intro.areas.continue_playground"),
+            { duration: 0 }
+          );
+        });
+      }, 250);
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "draw-area") {
+          var entity = context.hasEntity(context.selectedIDs()[0]);
+          if (entity && entity.nodes.length >= 6) {
+            return continueTo(finishPlayground);
           } else {
-            _multilingual.push(item);
+            return;
           }
+        } else if (mode.id === "select") {
+          _areaID = context.selectedIDs()[0];
+          return continueTo(searchPresets);
+        } else {
+          return chapter.restart();
         }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-      _multilingual.forEach(function(item2) {
-        if (item2.lang && existingLangs.has(item2.lang)) {
-          item2.value = "";
+    }
+    function finishPlayground() {
+      if (context.mode().id !== "draw-area") {
+        return chapter.restart();
+      }
+      _areaID = null;
+      var finishString = helpHtml("intro.areas.finish_area_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.areas.finish_playground");
+      revealPlayground(
+        playground,
+        finishString,
+        { duration: 250 }
+      );
+      timeout2(function() {
+        context.map().on("move.intro drawn.intro", function() {
+          revealPlayground(
+            playground,
+            finishString,
+            { duration: 0 }
+          );
+        });
+      }, 250);
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "draw-area") {
+          return;
+        } else if (mode.id === "select") {
+          _areaID = context.selectedIDs()[0];
+          return continueTo(searchPresets);
+        } else {
+          return chapter.restart();
         }
       });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
+      }
     }
-    function localized(selection2) {
-      _selection = selection2;
-      calcLocked();
-      var isLocked = field.locked();
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      input = wrap2.selectAll(".localized-main").data([0]);
-      input = input.enter().append("input").attr("type", "text").attr("id", field.domId).attr("class", "localized-main").call(utilNoAuto).merge(input);
-      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
-      var translateButton = wrap2.selectAll(".localized-add").data([0]);
-      translateButton = translateButton.enter().append("button").attr("class", "localized-add form-field-button").attr("aria-label", _t("icons.plus")).call(svgIcon("#iD-icon-plus")).merge(translateButton);
-      translateButton.classed("disabled", !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on("click", addNew);
-      if (_tags && !_multilingual.length) {
-        calcMultilingual(_tags);
+    function searchPresets() {
+      if (!_areaID || !context.hasEntity(_areaID)) {
+        return addArea();
       }
-      localizedInputs = selection2.selectAll(".localized-multilingual").data([0]);
-      localizedInputs = localizedInputs.enter().append("div").attr("class", "localized-multilingual").merge(localizedInputs);
-      localizedInputs.call(renderMultilingual);
-      localizedInputs.selectAll("button, input").classed("disabled", !!isLocked).attr("readonly", isLocked || null);
-      selection2.selectAll(".combobox-caret").classed("nope", true);
-      function addNew(d3_event) {
-        d3_event.preventDefault();
-        if (field.locked())
-          return;
-        var defaultLang = _mainLocalizer.languageCode().toLowerCase();
-        var langExists = _multilingual.find(function(datum2) {
-          return datum2.lang === defaultLang;
-        });
-        var isLangEn = defaultLang.indexOf("en") > -1;
-        if (isLangEn || langExists) {
-          defaultLang = "";
-          langExists = _multilingual.find(function(datum2) {
-            return datum2.lang === defaultLang;
-          });
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
+        context.enter(modeSelect(context, [_areaID]));
+      }
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      timeout2(function() {
+        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
+        context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
+        reveal(
+          ".preset-search-input",
+          helpHtml("intro.areas.search_playground", { preset: playgroundPreset.name() })
+        );
+      }, 400);
+      context.on("enter.intro", function(mode) {
+        if (!_areaID || !context.hasEntity(_areaID)) {
+          return continueTo(addArea);
         }
-        if (!langExists) {
-          _multilingual.unshift({ lang: defaultLang, value: "" });
-          localizedInputs.call(renderMultilingual);
+        var ids2 = context.selectedIDs();
+        if (mode.id !== "select" || !ids2.length || ids2[0] !== _areaID) {
+          context.enter(modeSelect(context, [_areaID]));
+          context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
+          context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+          context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
+          reveal(
+            ".preset-search-input",
+            helpHtml("intro.areas.search_playground", { preset: playgroundPreset.name() })
+          );
+          context.history().on("change.intro", null);
+        }
+      });
+      function checkPresetSearch() {
+        var first = context.container().select(".preset-list-item:first-child");
+        if (first.classed("preset-leisure-playground")) {
+          reveal(
+            first.select(".preset-list-button").node(),
+            helpHtml("intro.areas.choose_playground", { preset: playgroundPreset.name() }),
+            { duration: 300 }
+          );
+          context.container().select(".preset-search-input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
+          context.history().on("change.intro", function() {
+            continueTo(clickAddField);
+          });
         }
       }
-      function change(onInput) {
-        return function(d3_event) {
-          if (field.locked()) {
-            d3_event.preventDefault();
-            return;
-          }
-          var val = utilGetSetValue(select_default2(this));
-          if (!onInput)
-            val = context.cleanTagValue(val);
-          if (!val && Array.isArray(_tags[field.key]))
-            return;
-          var t = {};
-          t[field.key] = val || void 0;
-          dispatch10.call("change", this, t, onInput);
-        };
+      function continueTo(nextStep) {
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.on("enter.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
+        nextStep();
       }
     }
-    function key(lang) {
-      return field.key + ":" + lang;
-    }
-    function changeLang(d3_event, d) {
-      var tags = {};
-      var lang = utilGetSetValue(select_default2(this)).toLowerCase();
-      var language = _languagesArray.find(function(d2) {
-        return d2.label.toLowerCase() === lang || d2.localName && d2.localName.toLowerCase() === lang || d2.nativeName && d2.nativeName.toLowerCase() === lang;
-      });
-      if (language)
-        lang = language.code;
-      if (d.lang && d.lang !== lang) {
-        tags[key(d.lang)] = void 0;
+    function clickAddField() {
+      if (!_areaID || !context.hasEntity(_areaID)) {
+        return addArea();
       }
-      var newKey = lang && context.cleanTagKey(key(lang));
-      var value = utilGetSetValue(select_default2(this.parentNode).selectAll(".localized-value"));
-      if (newKey && value) {
-        tags[newKey] = value;
-      } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
-        tags[newKey] = _wikiTitles[d.lang];
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
+        return searchPresets();
+      }
+      if (!context.container().select(".form-field-description").empty()) {
+        return continueTo(describePlayground);
+      }
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      timeout2(function() {
+        context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+        var entity = context.entity(_areaID);
+        if (entity.tags.description) {
+          return continueTo(play);
+        }
+        var box = context.container().select(".more-fields").node().getBoundingClientRect();
+        if (box.top > 300) {
+          var pane = context.container().select(".entity-editor-pane .inspector-body");
+          var start2 = pane.node().scrollTop;
+          var end = start2 + (box.top - 300);
+          pane.transition().duration(250).tween("scroll.inspector", function() {
+            var node = this;
+            var i3 = number_default(start2, end);
+            return function(t2) {
+              node.scrollTop = i3(t2);
+            };
+          });
+        }
+        timeout2(function() {
+          reveal(
+            ".more-fields .combobox-input",
+            helpHtml("intro.areas.add_field", {
+              name: nameField.title(),
+              description: descriptionField.title()
+            }),
+            { duration: 300 }
+          );
+          context.container().select(".more-fields .combobox-input").on("click.intro", function() {
+            var watcher;
+            watcher = window.setInterval(function() {
+              if (!context.container().select("div.combobox").empty()) {
+                window.clearInterval(watcher);
+                continueTo(chooseDescriptionField);
+              }
+            }, 300);
+          });
+        }, 300);
+      }, 400);
+      context.on("exit.intro", function() {
+        return continueTo(searchPresets);
+      });
+      function continueTo(nextStep) {
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.container().select(".more-fields .combobox-input").on("click.intro", null);
+        context.on("exit.intro", null);
+        nextStep();
       }
-      d.lang = lang;
-      dispatch10.call("change", this, tags);
-    }
-    function changeValue(d3_event, d) {
-      if (!d.lang)
-        return;
-      var value = context.cleanTagValue(utilGetSetValue(select_default2(this))) || void 0;
-      if (!value && Array.isArray(d.value))
-        return;
-      var t = {};
-      t[key(d.lang)] = value;
-      d.value = value;
-      dispatch10.call("change", this, t);
     }
-    function fetchLanguages(value, cb) {
-      var v = value.toLowerCase();
-      var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
-      if (_countryCode && _territoryLanguages[_countryCode]) {
-        langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
+    function chooseDescriptionField() {
+      if (!_areaID || !context.hasEntity(_areaID)) {
+        return addArea();
       }
-      var langItems = [];
-      langCodes.forEach(function(code) {
-        var langItem = _languagesArray.find(function(item) {
-          return item.code === code;
-        });
-        if (langItem)
-          langItems.push(langItem);
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
+        return searchPresets();
+      }
+      if (!context.container().select(".form-field-description").empty()) {
+        return continueTo(describePlayground);
+      }
+      if (context.container().select("div.combobox").empty()) {
+        return continueTo(clickAddField);
+      }
+      var watcher;
+      watcher = window.setInterval(function() {
+        if (context.container().select("div.combobox").empty()) {
+          window.clearInterval(watcher);
+          timeout2(function() {
+            if (context.container().select(".form-field-description").empty()) {
+              continueTo(retryChooseDescription);
+            } else {
+              continueTo(describePlayground);
+            }
+          }, 300);
+        }
+      }, 300);
+      reveal(
+        "div.combobox",
+        helpHtml("intro.areas.choose_field", { field: descriptionField.title() }),
+        { duration: 300 }
+      );
+      context.on("exit.intro", function() {
+        return continueTo(searchPresets);
       });
-      langItems = utilArrayUniq(langItems.concat(_languagesArray));
-      cb(langItems.filter(function(d) {
-        return d.label.toLowerCase().indexOf(v) >= 0 || d.localName && d.localName.toLowerCase().indexOf(v) >= 0 || d.nativeName && d.nativeName.toLowerCase().indexOf(v) >= 0 || d.code.toLowerCase().indexOf(v) >= 0;
-      }).map(function(d) {
-        return { value: d.label };
-      }));
+      function continueTo(nextStep) {
+        if (watcher) window.clearInterval(watcher);
+        context.on("exit.intro", null);
+        nextStep();
+      }
     }
-    function renderMultilingual(selection2) {
-      var entries = selection2.selectAll("div.entry").data(_multilingual, function(d) {
-        return d.lang;
+    function describePlayground() {
+      if (!_areaID || !context.hasEntity(_areaID)) {
+        return addArea();
+      }
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
+        return searchPresets();
+      }
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      if (context.container().select(".form-field-description").empty()) {
+        return continueTo(retryChooseDescription);
+      }
+      context.on("exit.intro", function() {
+        continueTo(play);
       });
-      entries.exit().style("top", "0").style("max-height", "240px").transition().duration(200).style("opacity", "0").style("max-height", "0px").remove();
-      var entriesEnter = entries.enter().append("div").attr("class", "entry").each(function(_, index) {
-        var wrap2 = select_default2(this);
-        var domId = utilUniqueDomId(index);
-        var label = wrap2.append("label").attr("class", "field-label").attr("for", domId);
-        var text2 = label.append("span").attr("class", "label-text");
-        text2.append("span").attr("class", "label-textvalue").call(_t.append("translate.localized_translation_label"));
-        text2.append("span").attr("class", "label-textannotation");
-        label.append("button").attr("class", "remove-icon-multilingual").attr("title", _t("icons.remove")).on("click", function(d3_event, d) {
-          if (field.locked())
-            return;
-          d3_event.preventDefault();
-          _multilingual.splice(_multilingual.indexOf(d), 1);
-          var langKey = d.lang && key(d.lang);
-          if (langKey && langKey in _tags) {
-            delete _tags[langKey];
-            var t = {};
-            t[langKey] = void 0;
-            dispatch10.call("change", this, t);
-            return;
+      reveal(
+        ".entity-editor-pane",
+        helpHtml("intro.areas.describe_playground", { button: { html: icon("#iD-icon-close", "inline") } }),
+        { duration: 300 }
+      );
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
+      }
+    }
+    function retryChooseDescription() {
+      if (!_areaID || !context.hasEntity(_areaID)) {
+        return addArea();
+      }
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _areaID) {
+        return searchPresets();
+      }
+      context.container().select(".inspector-wrap .panewrap").style("right", "0%");
+      reveal(
+        ".entity-editor-pane",
+        helpHtml("intro.areas.retry_add_field", { field: descriptionField.title() }),
+        {
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            continueTo(clickAddField);
           }
-          renderMultilingual(selection2);
-        }).call(svgIcon("#iD-operation-delete"));
-        wrap2.append("input").attr("class", "localized-lang").attr("id", domId).attr("type", "text").attr("placeholder", _t("translate.localized_translation_language")).on("blur", changeLang).on("change", changeLang).call(langCombo);
-        wrap2.append("input").attr("type", "text").attr("class", "localized-value").on("blur", changeValue).on("change", changeValue);
-      });
-      entriesEnter.style("margin-top", "0px").style("max-height", "0px").style("opacity", "0").transition().duration(200).style("margin-top", "10px").style("max-height", "240px").style("opacity", "1").on("end", function() {
-        select_default2(this).style("max-height", "").style("overflow", "visible");
-      });
-      entries = entries.merge(entriesEnter);
-      entries.order();
-      entries.classed("present", true);
-      utilGetSetValue(entries.select(".localized-lang"), function(d) {
-        var langItem = _languagesArray.find(function(item) {
-          return item.code === d.lang;
-        });
-        if (langItem)
-          return langItem.label;
-        return d.lang;
-      });
-      utilGetSetValue(entries.select(".localized-value"), function(d) {
-        return typeof d.value === "string" ? d.value : "";
-      }).attr("title", function(d) {
-        return Array.isArray(d.value) ? d.value.filter(Boolean).join("\n") : null;
-      }).attr("placeholder", function(d) {
-        return Array.isArray(d.value) ? _t("inspector.multiple_values") : _t("translate.localized_translation_name");
-      }).classed("mixed", function(d) {
-        return Array.isArray(d.value);
+        }
+      );
+      context.on("exit.intro", function() {
+        return continueTo(searchPresets);
       });
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
+      }
     }
-    localized.tags = function(tags) {
-      _tags = tags;
-      if (typeof tags.wikipedia === "string" && !_wikiTitles) {
-        _wikiTitles = {};
-        var wm = tags.wikipedia.match(/([^:]+):(.+)/);
-        if (wm && wm[0] && wm[1]) {
-          wikipedia.translations(wm[1], wm[2], function(err, d) {
-            if (err || !d)
-              return;
-            _wikiTitles = d;
-          });
+    function play() {
+      dispatch14.call("done");
+      reveal(
+        ".ideditor",
+        helpHtml("intro.areas.play", { next: _t("intro.lines.title") }),
+        {
+          tooltipBox: ".intro-nav-wrap .chapter-line",
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            reveal(".ideditor");
+          }
         }
-      }
-      var isMixed = Array.isArray(tags[field.key]);
-      utilGetSetValue(input, typeof tags[field.key] === "string" ? tags[field.key] : "").attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
-      calcMultilingual(tags);
-      _selection.call(localized);
+      );
+    }
+    chapter.enter = function() {
+      addArea();
     };
-    localized.focus = function() {
-      input.node().focus();
+    chapter.exit = function() {
+      timeouts.forEach(window.clearTimeout);
+      context.on("enter.intro exit.intro", null);
+      context.map().on("move.intro drawn.intro", null);
+      context.history().on("change.intro", null);
+      context.container().select(".inspector-wrap").on("wheel.intro", null);
+      context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
+      context.container().select(".more-fields .combobox-input").on("click.intro", null);
     };
-    localized.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _multilingual = [];
-      loadCountryCode();
-      return localized;
+    chapter.restart = function() {
+      chapter.exit();
+      chapter.enter();
     };
-    function loadCountryCode() {
-      var extent = combinedEntityExtent();
-      var countryCode = extent && iso1A2Code(extent.center());
-      _countryCode = countryCode && countryCode.toLowerCase();
-    }
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    return utilRebind(localized, dispatch10, "on");
+    return utilRebind(chapter, dispatch14, "on");
   }
 
-  // modules/ui/fields/roadheight.js
-  function uiFieldRoadheight(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var primaryUnitInput = select_default2(null);
-    var primaryInput = select_default2(null);
-    var secondaryInput = select_default2(null);
-    var secondaryUnitInput = select_default2(null);
-    var _entityIDs = [];
-    var _tags;
-    var _isImperial;
-    var primaryUnits = [
-      {
-        value: "m",
-        title: _t("inspector.roadheight.meter")
-      },
-      {
-        value: "ft",
-        title: _t("inspector.roadheight.foot")
-      }
-    ];
-    var unitCombo = uiCombobox(context, "roadheight-unit").data(primaryUnits);
-    function roadheight(selection2) {
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      primaryInput = wrap2.selectAll("input.roadheight-number").data([0]);
-      primaryInput = primaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-number").attr("id", field.domId).call(utilNoAuto).merge(primaryInput);
-      primaryInput.on("change", change).on("blur", change);
-      var loc = combinedEntityExtent().center();
-      _isImperial = roadHeightUnit(loc) === "ft";
-      primaryUnitInput = wrap2.selectAll("input.roadheight-unit").data([0]);
-      primaryUnitInput = primaryUnitInput.enter().append("input").attr("type", "text").attr("class", "roadheight-unit").call(unitCombo).merge(primaryUnitInput);
-      primaryUnitInput.on("blur", changeUnits).on("change", changeUnits);
-      secondaryInput = wrap2.selectAll("input.roadheight-secondary-number").data([0]);
-      secondaryInput = secondaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-secondary-number").call(utilNoAuto).merge(secondaryInput);
-      secondaryInput.on("change", change).on("blur", change);
-      secondaryUnitInput = wrap2.selectAll("input.roadheight-secondary-unit").data([0]);
-      secondaryUnitInput = secondaryUnitInput.enter().append("input").attr("type", "text").call(utilNoAuto).classed("disabled", true).classed("roadheight-secondary-unit", true).attr("readonly", "readonly").merge(secondaryUnitInput);
-      function changeUnits() {
-        var primaryUnit = utilGetSetValue(primaryUnitInput);
-        if (primaryUnit === "m") {
-          _isImperial = false;
-        } else if (primaryUnit === "ft") {
-          _isImperial = true;
-        }
-        utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
-        setUnitSuggestions();
-        change();
-      }
+  // modules/ui/intro/line.js
+  function uiIntroLine(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var timeouts = [];
+    var _tulipRoadID = null;
+    var flowerRoadID = "w646";
+    var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
+    var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
+    var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
+    var roadCategory = _mainPresetIndex.item("category-road_minor");
+    var residentialPreset = _mainPresetIndex.item("highway/residential");
+    var woodRoadID = "w525";
+    var woodRoadEndID = "n2862";
+    var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
+    var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
+    var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
+    var washingtonStreetID = "w522";
+    var twelfthAvenueID = "w1";
+    var eleventhAvenueEndID = "n3550";
+    var twelfthAvenueEndID = "n5";
+    var _washingtonSegmentID = null;
+    var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
+    var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
+    var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
+    var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
+    var chapter = {
+      title: "intro.lines.title"
+    };
+    function timeout2(f2, t2) {
+      timeouts.push(window.setTimeout(f2, t2));
     }
-    function setUnitSuggestions() {
-      utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
+    function eventCancel(d3_event) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
     }
-    function change() {
-      var tag = {};
-      var primaryValue = utilGetSetValue(primaryInput).trim();
-      var secondaryValue = utilGetSetValue(secondaryInput).trim();
-      if (!primaryValue && !secondaryValue && Array.isArray(_tags[field.key]))
-        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 + '"');
-        }
-        tag[field.key] = primaryValue + secondaryValue;
+    function addLine() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      var msec = transitionTime(tulipRoadStart, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
+      }
+      context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
+      timeout2(function() {
+        var tooltip = reveal(
+          "button.add-line",
+          helpHtml("intro.lines.add_line")
+        );
+        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-lines");
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "add-line") return;
+          continueTo(startLine);
+        });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        nextStep();
       }
-      dispatch10.call("change", this, tag);
     }
-    roadheight.tags = function(tags) {
-      _tags = tags;
-      var primaryValue = tags[field.key];
-      var secondaryValue;
-      var isMixed = Array.isArray(primaryValue);
-      if (!isMixed) {
-        if (primaryValue && (primaryValue.indexOf("'") >= 0 || primaryValue.indexOf('"') >= 0)) {
-          secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
-          if (secondaryValue !== null) {
-            secondaryValue = secondaryValue[1];
-          }
-          primaryValue = primaryValue.match(/(-?[\d.]+)'/);
-          if (primaryValue !== null) {
-            primaryValue = primaryValue[1];
-          }
-          _isImperial = true;
-        } else if (primaryValue) {
-          _isImperial = false;
-        }
+    function startLine() {
+      if (context.mode().id !== "add-line") return chapter.restart();
+      _tulipRoadID = null;
+      var padding = 70 * Math.pow(2, context.map().zoom() - 18);
+      var box = pad(tulipRoadStart, padding, context);
+      box.height = box.height + 100;
+      var textId = context.lastPointerType() === "mouse" ? "start_line" : "start_line_tap";
+      var startLineString = helpHtml("intro.lines.missing_road") + "{br}" + helpHtml("intro.lines.line_draw_info") + helpHtml("intro.lines." + textId);
+      reveal(box, startLineString);
+      context.map().on("move.intro drawn.intro", function() {
+        padding = 70 * Math.pow(2, context.map().zoom() - 18);
+        box = pad(tulipRoadStart, padding, context);
+        box.height = box.height + 100;
+        reveal(box, startLineString, { duration: 0 });
+      });
+      context.on("enter.intro", function(mode) {
+        if (mode.id !== "draw-line") return chapter.restart();
+        continueTo(drawLine);
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-      setUnitSuggestions();
-      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");
-      secondaryUnitInput.attr("value", _isImperial ? _t("inspector.roadheight.inch") : null);
-    };
-    roadheight.focus = function() {
-      primaryInput.node().focus();
-    };
-    roadheight.entityIDs = function(val) {
-      _entityIDs = val;
-    };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
     }
-    return utilRebind(roadheight, dispatch10, "on");
-  }
-
-  // modules/ui/fields/roadspeed.js
-  function uiFieldRoadspeed(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var unitInput = select_default2(null);
-    var input = select_default2(null);
-    var _entityIDs = [];
-    var _tags;
-    var _isImperial;
-    var speedCombo = uiCombobox(context, "roadspeed");
-    var unitCombo = uiCombobox(context, "roadspeed-unit").data(["km/h", "mph"].map(comboValues));
-    var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
-    var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
-    function roadspeed(selection2) {
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      input = wrap2.selectAll("input.roadspeed-number").data([0]);
-      input = input.enter().append("input").attr("type", "text").attr("class", "roadspeed-number").attr("id", field.domId).call(utilNoAuto).call(speedCombo).merge(input);
-      input.on("change", change).on("blur", change);
-      var loc = combinedEntityExtent().center();
-      _isImperial = roadSpeedUnit(loc) === "mph";
-      unitInput = wrap2.selectAll("input.roadspeed-unit").data([0]);
-      unitInput = unitInput.enter().append("input").attr("type", "text").attr("class", "roadspeed-unit").attr("aria-label", _t("inspector.speed_unit")).call(unitCombo).merge(unitInput);
-      unitInput.on("blur", changeUnits).on("change", changeUnits);
-      function changeUnits() {
-        var unit2 = utilGetSetValue(unitInput);
-        if (unit2 === "km/h") {
-          _isImperial = false;
-        } else if (unit2 === "mph") {
-          _isImperial = true;
+    function drawLine() {
+      if (context.mode().id !== "draw-line") return chapter.restart();
+      _tulipRoadID = context.mode().selectedIDs()[0];
+      context.map().centerEase(tulipRoadMidpoint, 500);
+      timeout2(function() {
+        var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
+        var box = pad(tulipRoadMidpoint, padding, context);
+        box.height = box.height * 2;
+        reveal(
+          box,
+          helpHtml("intro.lines.intersect", { name: _t("intro.graph.name.flower-street") })
+        );
+        context.map().on("move.intro drawn.intro", function() {
+          padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
+          box = pad(tulipRoadMidpoint, padding, context);
+          box.height = box.height * 2;
+          reveal(
+            box,
+            helpHtml("intro.lines.intersect", { name: _t("intro.graph.name.flower-street") }),
+            { duration: 0 }
+          );
+        });
+      }, 550);
+      context.history().on("change.intro", function() {
+        if (isLineConnected()) {
+          continueTo(continueLine);
         }
-        utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
-        setUnitSuggestions();
-        change();
+      });
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "draw-line") {
+          return;
+        } else if (mode.id === "select") {
+          continueTo(retryIntersect);
+          return;
+        } else {
+          return chapter.restart();
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
     }
-    function setUnitSuggestions() {
-      speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
-      utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
-    }
-    function comboValues(d) {
-      return {
-        value: d.toString(),
-        title: d.toString()
-      };
+    function isLineConnected() {
+      var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
+      if (!entity) return false;
+      var drawNodes = context.graph().childNodes(entity);
+      return drawNodes.some(function(node) {
+        return context.graph().parentWays(node).some(function(parent) {
+          return parent.id === flowerRoadID;
+        });
+      });
     }
-    function change() {
-      var tag = {};
-      var value = utilGetSetValue(input).trim();
-      if (!value && Array.isArray(_tags[field.key]))
-        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");
-      }
-      dispatch10.call("change", this, tag);
+    function retryIntersect() {
+      select_default2(window).on("pointerdown.intro mousedown.intro", eventCancel, true);
+      var box = pad(tulipRoadIntersection, 80, context);
+      reveal(
+        box,
+        helpHtml("intro.lines.retry_intersect", { name: _t("intro.graph.name.flower-street") })
+      );
+      timeout2(chapter.restart, 3e3);
     }
-    roadspeed.tags = function(tags) {
-      _tags = tags;
-      var value = tags[field.key];
-      var isMixed = Array.isArray(value);
-      if (!isMixed) {
-        if (value && value.indexOf("mph") >= 0) {
-          value = parseInt(value, 10).toString();
-          _isImperial = true;
-        } else if (value) {
-          _isImperial = false;
+    function continueLine() {
+      if (context.mode().id !== "draw-line") return chapter.restart();
+      var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
+      if (!entity) return chapter.restart();
+      context.map().centerEase(tulipRoadIntersection, 500);
+      var continueLineText = helpHtml("intro.lines.continue_line") + "{br}" + helpHtml("intro.lines.finish_line_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.lines.finish_road");
+      reveal(".surface", continueLineText);
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "draw-line") {
+          return;
+        } else if (mode.id === "select") {
+          return continueTo(chooseCategoryRoad);
+        } else {
+          return chapter.restart();
         }
+      });
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        nextStep();
       }
-      setUnitSuggestions();
-      utilGetSetValue(input, typeof value === "string" ? value : "").attr("title", isMixed ? value.filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
-    };
-    roadspeed.focus = function() {
-      input.node().focus();
-    };
-    roadspeed.entityIDs = function(val) {
-      _entityIDs = val;
-    };
-    function combinedEntityExtent() {
-      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
-    }
-    return utilRebind(roadspeed, dispatch10, "on");
-  }
-
-  // modules/ui/fields/radio.js
-  function uiFieldRadio(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var placeholder = select_default2(null);
-    var wrap2 = select_default2(null);
-    var labels = select_default2(null);
-    var radios = select_default2(null);
-    var radioData = (field.options || field.keys).slice();
-    var typeField;
-    var layerField;
-    var _oldType = {};
-    var _entityIDs = [];
-    function selectedKey() {
-      var node = wrap2.selectAll(".form-field-input-radio label.active input");
-      return !node.empty() && node.datum();
     }
-    function radio(selection2) {
-      selection2.classed("preset-radio", true);
-      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      var enter = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-radio");
-      enter.append("span").attr("class", "placeholder");
-      wrap2 = wrap2.merge(enter);
-      placeholder = wrap2.selectAll(".placeholder");
-      labels = wrap2.selectAll("label").data(radioData);
-      enter = labels.enter().append("label");
-      enter.append("input").attr("type", "radio").attr("name", field.id).attr("value", function(d) {
-        return field.t("options." + d, { "default": d });
-      }).attr("checked", false);
-      enter.append("span").html(function(d) {
-        return field.t.html("options." + d, { "default": d });
+    function chooseCategoryRoad() {
+      if (context.mode().id !== "select") return chapter.restart();
+      context.on("exit.intro", function() {
+        return chapter.restart();
       });
-      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 layer = _mainPresetIndex.field("layer");
-      var showLayer = selected === "bridge" || selected === "tunnel" || tags.layer !== void 0;
-      var extrasWrap = selection2.selectAll(".structure-extras-wrap").data(selected ? [0] : []);
-      extrasWrap.exit().remove();
-      extrasWrap = extrasWrap.enter().append("div").attr("class", "structure-extras-wrap").merge(extrasWrap);
-      var list = extrasWrap.selectAll("ul").data([0]);
-      list = list.enter().append("ul").attr("class", "rows").merge(list);
-      if (type3) {
-        if (!typeField || typeField.id !== selected) {
-          typeField = uiField(context, type3, _entityIDs, { wrap: false }).on("change", changeType);
-        }
-        typeField.tags(tags);
-      } else {
-        typeField = null;
+      var button = context.container().select(".preset-category-road_minor .preset-list-button");
+      if (button.empty()) return chapter.restart();
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      timeout2(function() {
+        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
+        reveal(
+          button.node(),
+          helpHtml("intro.lines.choose_category_road", { category: roadCategory.name() })
+        );
+        button.on("click.intro", function() {
+          continueTo(choosePresetResidential);
+        });
+      }, 400);
+      function continueTo(nextStep) {
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.container().select(".preset-list-button").on("click.intro", null);
+        context.on("exit.intro", null);
+        nextStep();
       }
-      var typeItem = list.selectAll(".structure-type-item").data(typeField ? [typeField] : [], function(d) {
-        return d.id;
+    }
+    function choosePresetResidential() {
+      if (context.mode().id !== "select") return chapter.restart();
+      context.on("exit.intro", function() {
+        return chapter.restart();
       });
-      typeItem.exit().remove();
-      var typeEnter = typeItem.enter().insert("li", ":first-child").attr("class", "labeled-input structure-type-item");
-      typeEnter.append("span").attr("class", "label structure-label-type").attr("for", "preset-input-" + selected).call(_t.append("inspector.radio.structure.type"));
-      typeEnter.append("div").attr("class", "structure-input-type-wrap");
-      typeItem = typeItem.merge(typeEnter);
-      if (typeField) {
-        typeItem.selectAll(".structure-input-type-wrap").call(typeField.render);
+      var subgrid = context.container().select(".preset-category-road_minor .subgrid");
+      if (subgrid.empty()) return chapter.restart();
+      subgrid.selectAll(":not(.preset-highway-residential) .preset-list-button").on("click.intro", function() {
+        continueTo(retryPresetResidential);
+      });
+      subgrid.selectAll(".preset-highway-residential .preset-list-button").on("click.intro", function() {
+        continueTo(nameRoad);
+      });
+      timeout2(function() {
+        reveal(
+          subgrid.node(),
+          helpHtml("intro.lines.choose_preset_residential", { preset: residentialPreset.name() }),
+          { tooltipBox: ".preset-highway-residential .preset-list-button", duration: 300 }
+        );
+      }, 300);
+      function continueTo(nextStep) {
+        context.container().select(".preset-list-button").on("click.intro", null);
+        context.on("exit.intro", null);
+        nextStep();
       }
-      if (layer && showLayer) {
-        if (!layerField) {
-          layerField = uiField(context, layer, _entityIDs, { wrap: false }).on("change", changeLayer);
-        }
-        layerField.tags(tags);
-        field.keys = utilArrayUnion(field.keys, ["layer"]);
-      } else {
-        layerField = null;
-        field.keys = field.keys.filter(function(k) {
-          return k !== "layer";
+    }
+    function retryPresetResidential() {
+      if (context.mode().id !== "select") return chapter.restart();
+      context.on("exit.intro", function() {
+        return chapter.restart();
+      });
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      timeout2(function() {
+        var button = context.container().select(".entity-editor-pane .preset-list-button");
+        reveal(
+          button.node(),
+          helpHtml("intro.lines.retry_preset_residential", { preset: residentialPreset.name() })
+        );
+        button.on("click.intro", function() {
+          continueTo(chooseCategoryRoad);
         });
-      }
-      var layerItem = list.selectAll(".structure-layer-item").data(layerField ? [layerField] : []);
-      layerItem.exit().remove();
-      var layerEnter = layerItem.enter().append("li").attr("class", "labeled-input structure-layer-item");
-      layerEnter.append("span").attr("class", "label structure-label-layer").attr("for", "preset-input-layer").call(_t.append("inspector.radio.structure.layer"));
-      layerEnter.append("div").attr("class", "structure-input-layer-wrap");
-      layerItem = layerItem.merge(layerEnter);
-      if (layerField) {
-        layerItem.selectAll(".structure-input-layer-wrap").call(layerField.render);
+      }, 500);
+      function continueTo(nextStep) {
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.container().select(".preset-list-button").on("click.intro", null);
+        context.on("exit.intro", null);
+        nextStep();
       }
     }
-    function changeType(t, onInput) {
-      var key = selectedKey();
-      if (!key)
-        return;
-      var val = t[key];
-      if (val !== "no") {
-        _oldType[key] = val;
+    function nameRoad() {
+      context.on("exit.intro", function() {
+        continueTo(didNameRoad);
+      });
+      timeout2(function() {
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.lines.name_road", { button: { html: icon("#iD-icon-close", "inline") } }),
+          { tooltipClass: "intro-lines-name_road" }
+        );
+      }, 500);
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
       }
-      if (field.type === "structureRadio") {
-        if (val === "no" || key !== "bridge" && key !== "tunnel" || key === "tunnel" && val === "building_passage") {
-          t.layer = void 0;
-        }
-        if (t.layer === void 0) {
-          if (key === "bridge" && val !== "no") {
-            t.layer = "1";
-          }
-          if (key === "tunnel" && val !== "no" && val !== "building_passage") {
-            t.layer = "-1";
+    }
+    function didNameRoad() {
+      context.history().checkpoint("doneAddLine");
+      timeout2(function() {
+        reveal(".surface", helpHtml("intro.lines.did_name_road"), {
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            continueTo(updateLine);
           }
-        }
+        });
+      }, 500);
+      function continueTo(nextStep) {
+        nextStep();
       }
-      dispatch10.call("change", this, t, onInput);
     }
-    function changeLayer(t, onInput) {
-      if (t.layer === "0") {
-        t.layer = void 0;
+    function updateLine() {
+      context.history().reset("doneAddLine");
+      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+        return chapter.restart();
       }
-      dispatch10.call("change", this, t, onInput);
-    }
-    function changeRadio() {
-      var t = {};
-      var activeKey;
-      if (field.key) {
-        t[field.key] = void 0;
+      var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
       }
-      radios.each(function(d) {
-        var active = select_default2(this).property("checked");
-        if (active)
-          activeKey = d;
-        if (field.key) {
-          if (active)
-            t[field.key] = d;
-        } else {
-          var val = _oldType[activeKey] || "yes";
-          t[d] = active ? val : void 0;
-        }
-      });
-      if (field.type === "structureRadio") {
-        if (activeKey === "bridge") {
-          t.layer = "1";
-        } else if (activeKey === "tunnel" && t.tunnel !== "building_passage") {
-          t.layer = "-1";
-        } else {
-          t.layer = void 0;
-        }
+      context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
+      timeout2(function() {
+        var padding = 250 * Math.pow(2, context.map().zoom() - 19);
+        var box = pad(woodRoadDragMidpoint, padding, context);
+        var advance = function() {
+          continueTo(addNode);
+        };
+        reveal(
+          box,
+          helpHtml("intro.lines.update_line"),
+          { buttonText: _t.html("intro.ok"), buttonCallback: advance }
+        );
+        context.map().on("move.intro drawn.intro", function() {
+          var padding2 = 250 * Math.pow(2, context.map().zoom() - 19);
+          var box2 = pad(woodRoadDragMidpoint, padding2, context);
+          reveal(
+            box2,
+            helpHtml("intro.lines.update_line"),
+            { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
+          );
+        });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
       }
-      dispatch10.call("change", this, t);
     }
-    radio.tags = function(tags) {
-      function isOptionChecked(d) {
-        if (field.key) {
-          return tags[field.key] === d;
-        }
-        return !!(typeof tags[d] === "string" && tags[d].toLowerCase() !== "no");
-      }
-      function isMixed(d) {
-        if (field.key) {
-          return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
-        }
-        return Array.isArray(tags[d]);
+    function addNode() {
+      context.history().reset("doneAddLine");
+      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+        return chapter.restart();
       }
-      radios.property("checked", function(d) {
-        return isOptionChecked(d) && (field.key || field.options.filter(isOptionChecked).length === 1);
+      var padding = 40 * Math.pow(2, context.map().zoom() - 19);
+      var box = pad(woodRoadAddNode, padding, context);
+      var addNodeString = helpHtml("intro.lines.add_node" + (context.lastPointerType() === "mouse" ? "" : "_touch"));
+      reveal(box, addNodeString);
+      context.map().on("move.intro drawn.intro", function() {
+        var padding2 = 40 * Math.pow(2, context.map().zoom() - 19);
+        var box2 = pad(woodRoadAddNode, padding2, context);
+        reveal(box2, addNodeString, { duration: 0 });
       });
-      labels.classed("active", function(d) {
-        if (field.key) {
-          return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
+      context.history().on("change.intro", function(changed) {
+        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+          return continueTo(updateLine);
+        }
+        if (changed.created().length === 1) {
+          timeout2(function() {
+            continueTo(startDragEndpoint);
+          }, 500);
         }
-        return Array.isArray(tags[d]) && tags[d].some((v) => typeof v === "string" && v.toLowerCase() !== "no") || !!(typeof tags[d] === "string" && tags[d].toLowerCase() !== "no");
-      }).classed("mixed", isMixed).attr("title", function(d) {
-        return isMixed(d) ? _t("inspector.unshared_value_tooltip") : null;
       });
-      var selection2 = radios.filter(function() {
-        return this.checked;
+      context.on("enter.intro", function(mode) {
+        if (mode.id !== "select") {
+          continueTo(updateLine);
+        }
       });
-      if (selection2.empty()) {
-        placeholder.text("");
-        placeholder.call(_t.append("inspector.none"));
-      } else {
-        placeholder.text(selection2.attr("value"));
-        _oldType[selection2.datum()] = tags[selection2.datum()];
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-      if (field.type === "structureRadio") {
-        if (!!tags.waterway && !_oldType.tunnel) {
-          _oldType.tunnel = "culvert";
+    }
+    function startDragEndpoint() {
+      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+        return continueTo(updateLine);
+      }
+      var padding = 100 * Math.pow(2, context.map().zoom() - 19);
+      var box = pad(woodRoadDragEndpoint, padding, context);
+      var startDragString = helpHtml("intro.lines.start_drag_endpoint" + (context.lastPointerType() === "mouse" ? "" : "_touch")) + helpHtml("intro.lines.drag_to_intersection");
+      reveal(box, startDragString);
+      context.map().on("move.intro drawn.intro", function() {
+        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+          return continueTo(updateLine);
         }
-        wrap2.call(structureExtras, tags);
+        var padding2 = 100 * Math.pow(2, context.map().zoom() - 19);
+        var box2 = pad(woodRoadDragEndpoint, padding2, context);
+        reveal(box2, startDragString, { duration: 0 });
+        var entity = context.entity(woodRoadEndID);
+        if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
+          continueTo(finishDragEndpoint);
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
       }
-    };
-    radio.focus = function() {
-      radios.node().focus();
-    };
-    radio.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _oldType = {};
-      return radio;
-    };
-    radio.isAllowed = function() {
-      return _entityIDs.length === 1;
-    };
-    return utilRebind(radio, dispatch10, "on");
-  }
-
-  // modules/ui/fields/restrictions.js
-  function uiFieldRestrictions(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var breathe = behaviorBreathe(context);
-    corePreferences("turn-restriction-via-way", null);
-    var storedViaWay = corePreferences("turn-restriction-via-way0");
-    var storedDistance = corePreferences("turn-restriction-distance");
-    var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
-    var _maxDistance = storedDistance ? +storedDistance : 30;
-    var _initialized2 = false;
-    var _parent = select_default2(null);
-    var _container = select_default2(null);
-    var _oldTurns;
-    var _graph;
-    var _vertexID;
-    var _intersection;
-    var _fromWayID;
-    var _lastXPos;
-    function restrictions(selection2) {
-      _parent = selection2;
-      if (_vertexID && (context.graph() !== _graph || !_intersection)) {
-        _graph = context.graph();
-        _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
+    }
+    function finishDragEndpoint() {
+      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+        return continueTo(updateLine);
       }
-      var isOK = _intersection && _intersection.vertices.length && _intersection.vertices.filter(function(vertex) {
-        return vertex.id === _vertexID;
-      }).length && _intersection.ways.length > 2 && _intersection.ways.filter(function(way) {
-        return way.__to;
-      }).length > 1;
-      select_default2(selection2.node().parentNode).classed("hide", !isOK);
-      if (!isOK || !context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode || !selection2.node().parentNode.parentNode) {
-        selection2.call(restrictions.off);
-        return;
+      var padding = 100 * Math.pow(2, context.map().zoom() - 19);
+      var box = pad(woodRoadDragEndpoint, padding, context);
+      var finishDragString = helpHtml("intro.lines.spot_looks_good") + helpHtml("intro.lines.finish_drag_endpoint" + (context.lastPointerType() === "mouse" ? "" : "_touch"));
+      reveal(box, finishDragString);
+      context.map().on("move.intro drawn.intro", function() {
+        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+          return continueTo(updateLine);
+        }
+        var padding2 = 100 * Math.pow(2, context.map().zoom() - 19);
+        var box2 = pad(woodRoadDragEndpoint, padding2, context);
+        reveal(box2, finishDragString, { duration: 0 });
+        var entity = context.entity(woodRoadEndID);
+        if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
+          continueTo(startDragEndpoint);
+        }
+      });
+      context.on("enter.intro", function() {
+        continueTo(startDragMidpoint);
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var container = wrap2.selectAll(".restriction-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "restriction-container");
-      containerEnter.append("div").attr("class", "restriction-help");
-      _container = containerEnter.merge(container).call(renderViewer);
-      var controls = wrap2.selectAll(".restriction-controls").data([0]);
-      controls.enter().append("div").attr("class", "restriction-controls-container").append("div").attr("class", "restriction-controls").merge(controls).call(renderControls);
     }
-    function renderControls(selection2) {
-      var distControl = selection2.selectAll(".restriction-distance").data([0]);
-      distControl.exit().remove();
-      var distControlEnter = distControl.enter().append("div").attr("class", "restriction-control restriction-distance");
-      distControlEnter.append("span").attr("class", "restriction-control-label restriction-distance-label").call(_t.append("restriction.controls.distance", { suffix: ":" }));
-      distControlEnter.append("input").attr("class", "restriction-distance-input").attr("type", "range").attr("min", "20").attr("max", "50").attr("step", "5");
-      distControlEnter.append("span").attr("class", "restriction-distance-text");
-      selection2.selectAll(".restriction-distance-input").property("value", _maxDistance).on("input", function() {
-        var val = select_default2(this).property("value");
-        _maxDistance = +val;
-        _intersection = null;
-        _container.selectAll(".layer-osm .layer-turns *").remove();
-        corePreferences("turn-restriction-distance", _maxDistance);
-        _parent.call(restrictions);
+    function startDragMidpoint() {
+      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+        return continueTo(updateLine);
+      }
+      if (context.selectedIDs().indexOf(woodRoadID) === -1) {
+        context.enter(modeSelect(context, [woodRoadID]));
+      }
+      var padding = 80 * Math.pow(2, context.map().zoom() - 19);
+      var box = pad(woodRoadDragMidpoint, padding, context);
+      reveal(box, helpHtml("intro.lines.start_drag_midpoint"));
+      context.map().on("move.intro drawn.intro", function() {
+        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+          return continueTo(updateLine);
+        }
+        var padding2 = 80 * Math.pow(2, context.map().zoom() - 19);
+        var box2 = pad(woodRoadDragMidpoint, padding2, context);
+        reveal(box2, helpHtml("intro.lines.start_drag_midpoint"), { duration: 0 });
       });
-      selection2.selectAll(".restriction-distance-text").call(displayMaxDistance(_maxDistance));
-      var viaControl = selection2.selectAll(".restriction-via-way").data([0]);
-      viaControl.exit().remove();
-      var viaControlEnter = viaControl.enter().append("div").attr("class", "restriction-control restriction-via-way");
-      viaControlEnter.append("span").attr("class", "restriction-control-label restriction-via-way-label").call(_t.append("restriction.controls.via", { suffix: ":" }));
-      viaControlEnter.append("input").attr("class", "restriction-via-way-input").attr("type", "range").attr("min", "0").attr("max", "2").attr("step", "1");
-      viaControlEnter.append("span").attr("class", "restriction-via-way-text");
-      selection2.selectAll(".restriction-via-way-input").property("value", _maxViaWay).on("input", function() {
-        var val = select_default2(this).property("value");
-        _maxViaWay = +val;
-        _container.selectAll(".layer-osm .layer-turns *").remove();
-        corePreferences("turn-restriction-via-way0", _maxViaWay);
-        _parent.call(restrictions);
+      context.history().on("change.intro", function(changed) {
+        if (changed.created().length === 1) {
+          continueTo(continueDragMidpoint);
+        }
       });
-      selection2.selectAll(".restriction-via-way-text").call(displayMaxVia(_maxViaWay));
+      context.on("enter.intro", function(mode) {
+        if (mode.id !== "select") {
+          context.enter(modeSelect(context, [woodRoadID]));
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
+      }
     }
-    function renderViewer(selection2) {
-      if (!_intersection)
-        return;
-      var vgraph = _intersection.graph;
-      var filter2 = utilFunctor(true);
-      var projection2 = geoRawMercator();
-      var sdims = utilGetDimensions(context.container().select(".sidebar"));
-      var d = [sdims[0] - 50, 370];
-      var c = geoVecScale(d, 0.5);
-      var z = 22;
-      projection2.scale(geoZoomToScale(z));
-      var extent = geoExtent();
-      for (var i2 = 0; i2 < _intersection.vertices.length; i2++) {
-        extent._extend(_intersection.vertices[i2].extent());
+    function continueDragMidpoint() {
+      if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+        return continueTo(updateLine);
       }
-      var padTop = 35;
-      if (_intersection.vertices.length > 1) {
-        var hPadding = Math.min(160, Math.max(110, d[0] * 0.4));
-        var vPadding = 160;
-        var tl = projection2([extent[0][0], extent[1][1]]);
-        var br = projection2([extent[1][0], extent[0][1]]);
-        var hFactor = (br[0] - tl[0]) / (d[0] - hPadding);
-        var vFactor = (br[1] - tl[1]) / (d[1] - vPadding - padTop);
-        var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
-        var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
-        z = z - Math.max(hZoomDiff, vZoomDiff);
-        projection2.scale(geoZoomToScale(z));
+      var padding = 100 * Math.pow(2, context.map().zoom() - 19);
+      var box = pad(woodRoadDragEndpoint, padding, context);
+      box.height += 400;
+      var advance = function() {
+        context.history().checkpoint("doneUpdateLine");
+        continueTo(deleteLines);
+      };
+      reveal(
+        box,
+        helpHtml("intro.lines.continue_drag_midpoint"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: advance }
+      );
+      context.map().on("move.intro drawn.intro", function() {
+        if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
+          return continueTo(updateLine);
+        }
+        var padding2 = 100 * Math.pow(2, context.map().zoom() - 19);
+        var box2 = pad(woodRoadDragEndpoint, padding2, context);
+        box2.height += 400;
+        reveal(
+          box2,
+          helpHtml("intro.lines.continue_drag_midpoint"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
+        );
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
       }
-      var extentCenter = projection2(extent.center());
-      extentCenter[1] = extentCenter[1] - padTop / 2;
-      projection2.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
-      var drawLayers = svgLayers(projection2, context).only(["osm", "touch"]).dimensions(d);
-      var drawVertices = svgVertices(projection2, context);
-      var drawLines = svgLines(projection2, context);
-      var drawTurns = svgTurns(projection2, context);
-      var firstTime = selection2.selectAll(".surface").empty();
-      selection2.call(drawLayers);
-      var surface = selection2.selectAll(".surface").classed("tr", true);
-      if (firstTime) {
-        _initialized2 = true;
-        surface.call(breathe);
+    }
+    function deleteLines() {
+      context.history().reset("doneUpdateLine");
+      context.enter(modeBrowse(context));
+      if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+        return chapter.restart();
       }
-      if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
-        _fromWayID = null;
-        _oldTurns = null;
+      var msec = transitionTime(deleteLinesLoc, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
       }
-      surface.call(utilSetDimensions, d).call(drawVertices, vgraph, _intersection.vertices, filter2, extent, z).call(drawLines, vgraph, _intersection.ways, filter2).call(drawTurns, vgraph, _intersection.turns(_fromWayID, _maxViaWay));
-      surface.on("click.restrictions", click).on("mouseover.restrictions", mouseover);
-      surface.selectAll(".selected").classed("selected", false);
-      surface.selectAll(".related").classed("related", false);
-      var way;
-      if (_fromWayID) {
-        way = vgraph.entity(_fromWayID);
-        surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+      context.map().centerZoomEase(deleteLinesLoc, 18, msec);
+      timeout2(function() {
+        var padding = 200 * Math.pow(2, context.map().zoom() - 18);
+        var box = pad(deleteLinesLoc, padding, context);
+        box.top -= 200;
+        box.height += 400;
+        var advance = function() {
+          continueTo(rightClickIntersection);
+        };
+        reveal(
+          box,
+          helpHtml("intro.lines.delete_lines", { street: _t("intro.graph.name.12th-avenue") }),
+          { buttonText: _t.html("intro.ok"), buttonCallback: advance }
+        );
+        context.map().on("move.intro drawn.intro", function() {
+          var padding2 = 200 * Math.pow(2, context.map().zoom() - 18);
+          var box2 = pad(deleteLinesLoc, padding2, context);
+          box2.top -= 200;
+          box2.height += 400;
+          reveal(
+            box2,
+            helpHtml("intro.lines.delete_lines", { street: _t("intro.graph.name.12th-avenue") }),
+            { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
+          );
+        });
+        context.history().on("change.intro", function() {
+          timeout2(function() {
+            continueTo(deleteLines);
+          }, 500);
+        });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-      document.addEventListener("resizeWindow", function() {
-        utilSetDimensions(_container, null);
-        redraw(1);
-      }, false);
-      updateHints(null);
-      function click(d3_event) {
-        surface.call(breathe.off).call(breathe);
-        var datum2 = d3_event.target.__data__;
-        var entity = datum2 && datum2.properties && datum2.properties.entity;
-        if (entity) {
-          datum2 = entity;
+    }
+    function rightClickIntersection() {
+      context.history().reset("doneUpdateLine");
+      context.enter(modeBrowse(context));
+      context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
+      var rightClickString = helpHtml("intro.lines.split_street", {
+        street1: _t("intro.graph.name.11th-avenue"),
+        street2: _t("intro.graph.name.washington-street")
+      }) + helpHtml("intro.lines." + (context.lastPointerType() === "mouse" ? "rightclick_intersection" : "edit_menu_intersection_touch"));
+      timeout2(function() {
+        var padding = 60 * Math.pow(2, context.map().zoom() - 18);
+        var box = pad(eleventhAvenueEnd, padding, context);
+        reveal(box, rightClickString);
+        context.map().on("move.intro drawn.intro", function() {
+          var padding2 = 60 * Math.pow(2, context.map().zoom() - 18);
+          var box2 = pad(eleventhAvenueEnd, padding2, context);
+          reveal(
+            box2,
+            rightClickString,
+            { duration: 0 }
+          );
+        });
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "select") return;
+          var ids = context.selectedIDs();
+          if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
+          timeout2(function() {
+            var node = selectMenuItem(context, "split").node();
+            if (!node) return;
+            continueTo(splitIntersection);
+          }, 50);
+        });
+        context.history().on("change.intro", function() {
+          timeout2(function() {
+            continueTo(deleteLines);
+          }, 300);
+        });
+      }, 600);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
+    }
+    function splitIntersection() {
+      if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+        return continueTo(deleteLines);
+      }
+      var node = selectMenuItem(context, "split").node();
+      if (!node) {
+        return continueTo(rightClickIntersection);
+      }
+      var wasChanged = false;
+      _washingtonSegmentID = null;
+      reveal(
+        ".edit-menu",
+        helpHtml(
+          "intro.lines.split_intersection",
+          { street: _t("intro.graph.name.washington-street") }
+        ),
+        { padding: 50 }
+      );
+      context.map().on("move.intro drawn.intro", function() {
+        var node2 = selectMenuItem(context, "split").node();
+        if (!wasChanged && !node2) {
+          return continueTo(rightClickIntersection);
         }
-        if (datum2 instanceof osmWay && (datum2.__from || datum2.__via)) {
-          _fromWayID = datum2.id;
-          _oldTurns = null;
-          redraw();
-        } else if (datum2 instanceof osmTurn) {
-          var actions, extraActions, turns, i3;
-          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
-          if (datum2.restrictionID && !datum2.direct) {
-            return;
-          } else if (datum2.restrictionID && !datum2.only) {
-            var seen = {};
-            var datumOnly = JSON.parse(JSON.stringify(datum2));
-            datumOnly.only = true;
-            restrictionType = restrictionType.replace(/^no/, "only");
-            turns = _intersection.turns(_fromWayID, 2);
-            extraActions = [];
-            _oldTurns = [];
-            for (i3 = 0; i3 < turns.length; i3++) {
-              var turn = turns[i3];
-              if (seen[turn.restrictionID])
-                continue;
-              if (turn.direct && turn.path[1] === datum2.path[1]) {
-                seen[turns[i3].restrictionID] = true;
-                turn.restrictionType = osmInferRestriction(vgraph, turn, projection2);
-                _oldTurns.push(turn);
-                extraActions.push(actionUnrestrictTurn(turn));
-              }
-            }
-            actions = _intersection.actions.concat(extraActions, [
-              actionRestrictTurn(datumOnly, restrictionType),
-              _t("operations.restriction.annotation.create")
-            ]);
-          } else if (datum2.restrictionID) {
-            turns = _oldTurns || [];
-            extraActions = [];
-            for (i3 = 0; i3 < turns.length; i3++) {
-              if (turns[i3].key !== datum2.key) {
-                extraActions.push(actionRestrictTurn(turns[i3], turns[i3].restrictionType));
-              }
-            }
-            _oldTurns = null;
-            actions = _intersection.actions.concat(extraActions, [
-              actionUnrestrictTurn(datum2),
-              _t("operations.restriction.annotation.delete")
-            ]);
+        reveal(
+          ".edit-menu",
+          helpHtml(
+            "intro.lines.split_intersection",
+            { street: _t("intro.graph.name.washington-street") }
+          ),
+          { duration: 0, padding: 50 }
+        );
+      });
+      context.history().on("change.intro", function(changed) {
+        wasChanged = true;
+        timeout2(function() {
+          if (context.history().undoAnnotation() === _t("operations.split.annotation.line", { n: 1 })) {
+            _washingtonSegmentID = changed.created()[0].id;
+            continueTo(didSplit);
           } else {
-            actions = _intersection.actions.concat([
-              actionRestrictTurn(datum2, restrictionType),
-              _t("operations.restriction.annotation.create")
-            ]);
+            _washingtonSegmentID = null;
+            continueTo(retrySplit);
           }
-          context.perform.apply(context, actions);
-          var s = surface.selectAll("." + datum2.key);
-          datum2 = s.empty() ? null : s.datum();
-          updateHints(datum2);
-        } else {
-          _fromWayID = null;
-          _oldTurns = null;
-          redraw();
-        }
+        }, 300);
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-      function mouseover(d3_event) {
-        var datum2 = d3_event.target.__data__;
-        updateHints(datum2);
+    }
+    function retrySplit() {
+      context.enter(modeBrowse(context));
+      context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
+      var advance = function() {
+        continueTo(rightClickIntersection);
+      };
+      var padding = 60 * Math.pow(2, context.map().zoom() - 18);
+      var box = pad(eleventhAvenueEnd, padding, context);
+      reveal(
+        box,
+        helpHtml("intro.lines.retry_split"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: advance }
+      );
+      context.map().on("move.intro drawn.intro", function() {
+        var padding2 = 60 * Math.pow(2, context.map().zoom() - 18);
+        var box2 = pad(eleventhAvenueEnd, padding2, context);
+        reveal(
+          box2,
+          helpHtml("intro.lines.retry_split"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: advance }
+        );
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
       }
-      _lastXPos = _lastXPos || sdims[0];
-      function redraw(minChange) {
-        var xPos = -1;
-        if (minChange) {
-          xPos = utilGetDimensions(context.container().select(".sidebar"))[0];
-        }
-        if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
-          if (context.hasEntity(_vertexID)) {
-            _lastXPos = xPos;
-            _container.call(renderViewer);
-          }
-        }
+    }
+    function didSplit() {
+      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+        return continueTo(rightClickIntersection);
       }
-      function highlightPathsFrom(wayID) {
-        surface.selectAll(".related").classed("related", false).classed("allow", false).classed("restrict", false).classed("only", false);
-        surface.selectAll("." + wayID).classed("related", true);
-        if (wayID) {
-          var turns = _intersection.turns(wayID, _maxViaWay);
-          for (var i3 = 0; i3 < turns.length; i3++) {
-            var turn = turns[i3];
-            var ids = [turn.to.way];
-            var klass = turn.no ? "restrict" : turn.only ? "only" : "allow";
-            if (turn.only || turns.length === 1) {
-              if (turn.via.ways) {
-                ids = ids.concat(turn.via.ways);
-              }
-            } else if (turn.to.way === wayID) {
-              continue;
-            }
-            surface.selectAll(utilEntitySelector(ids)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
-          }
-        }
-      }
-      function updateHints(datum2) {
-        var help = _container.selectAll(".restriction-help").html("");
-        var placeholders = {};
-        ["from", "via", "to"].forEach(function(k) {
-          placeholders[k] = { html: '<span class="qualifier">' + _t("restriction.help." + k) + "</span>" };
+      var ids = context.selectedIDs();
+      var string = "intro.lines.did_split_" + (ids.length > 1 ? "multi" : "single");
+      var street = _t("intro.graph.name.washington-street");
+      var padding = 200 * Math.pow(2, context.map().zoom() - 18);
+      var box = pad(twelfthAvenue, padding, context);
+      box.width = box.width / 2;
+      reveal(
+        box,
+        helpHtml(string, { street1: street, street2: street }),
+        { duration: 500 }
+      );
+      timeout2(function() {
+        context.map().centerZoomEase(twelfthAvenue, 18, 500);
+        context.map().on("move.intro drawn.intro", function() {
+          var padding2 = 200 * Math.pow(2, context.map().zoom() - 18);
+          var box2 = pad(twelfthAvenue, padding2, context);
+          box2.width = box2.width / 2;
+          reveal(
+            box2,
+            helpHtml(string, { street1: street, street2: street }),
+            { duration: 0 }
+          );
         });
-        var entity = datum2 && datum2.properties && datum2.properties.entity;
-        if (entity) {
-          datum2 = entity;
+      }, 600);
+      context.on("enter.intro", function() {
+        var ids2 = context.selectedIDs();
+        if (ids2.length === 1 && ids2[0] === _washingtonSegmentID) {
+          continueTo(multiSelect2);
         }
-        if (_fromWayID) {
-          way = vgraph.entity(_fromWayID);
-          surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+      });
+      context.history().on("change.intro", function() {
+        if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+          return continueTo(rightClickIntersection);
         }
-        if (datum2 instanceof osmWay && datum2.__from) {
-          way = datum2;
-          highlightPathsFrom(_fromWayID ? null : way.id);
-          surface.selectAll("." + way.id).classed("related", true);
-          var clickSelect = !_fromWayID || _fromWayID !== way.id;
-          help.append("div").html(_t.html("restriction.help." + (clickSelect ? "select_from_name" : "from_name"), {
-            from: placeholders.from,
-            fromName: displayName(way.id, vgraph)
-          }));
-        } else if (datum2 instanceof osmTurn) {
-          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
-          var turnType = restrictionType.replace(/^(only|no)\_/, "");
-          var indirect = datum2.direct === false ? _t.html("restriction.help.indirect") : "";
-          var klass, turnText, nextText;
-          if (datum2.no) {
-            klass = "restrict";
-            turnText = _t.html("restriction.help.turn.no_" + turnType, { indirect: { html: indirect } });
-            nextText = _t.html("restriction.help.turn.only_" + turnType, { indirect: "" });
-          } else if (datum2.only) {
-            klass = "only";
-            turnText = _t.html("restriction.help.turn.only_" + turnType, { indirect: { html: indirect } });
-            nextText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: "" });
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
+    }
+    function multiSelect2() {
+      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+        return continueTo(rightClickIntersection);
+      }
+      var ids = context.selectedIDs();
+      var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
+      var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
+      if (hasWashington && hasTwelfth) {
+        return continueTo(multiRightClick);
+      } else if (!hasWashington && !hasTwelfth) {
+        return continueTo(didSplit);
+      }
+      context.map().centerZoomEase(twelfthAvenue, 18, 500);
+      timeout2(function() {
+        var selected, other, padding, box;
+        if (hasWashington) {
+          selected = _t("intro.graph.name.washington-street");
+          other = _t("intro.graph.name.12th-avenue");
+          padding = 60 * Math.pow(2, context.map().zoom() - 18);
+          box = pad(twelfthAvenueEnd, padding, context);
+          box.width *= 3;
+        } else {
+          selected = _t("intro.graph.name.12th-avenue");
+          other = _t("intro.graph.name.washington-street");
+          padding = 200 * Math.pow(2, context.map().zoom() - 18);
+          box = pad(twelfthAvenue, padding, context);
+          box.width /= 2;
+        }
+        reveal(
+          box,
+          helpHtml(
+            "intro.lines.multi_select",
+            { selected, other1: other }
+          ) + " " + helpHtml(
+            "intro.lines.add_to_selection_" + (context.lastPointerType() === "mouse" ? "click" : "touch"),
+            { selected, other2: other }
+          )
+        );
+        context.map().on("move.intro drawn.intro", function() {
+          if (hasWashington) {
+            selected = _t("intro.graph.name.washington-street");
+            other = _t("intro.graph.name.12th-avenue");
+            padding = 60 * Math.pow(2, context.map().zoom() - 18);
+            box = pad(twelfthAvenueEnd, padding, context);
+            box.width *= 3;
           } else {
-            klass = "allow";
-            turnText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: { html: indirect } });
-            nextText = _t.html("restriction.help.turn.no_" + turnType, { indirect: "" });
-          }
-          help.append("div").attr("class", "qualifier " + klass).html(turnText);
-          help.append("div").html(_t.html("restriction.help.from_name_to_name", {
-            from: placeholders.from,
-            fromName: displayName(datum2.from.way, vgraph),
-            to: placeholders.to,
-            toName: displayName(datum2.to.way, vgraph)
-          }));
-          if (datum2.via.ways && datum2.via.ways.length) {
-            var names = [];
-            for (var i3 = 0; i3 < datum2.via.ways.length; i3++) {
-              var prev = names[names.length - 1];
-              var curr = displayName(datum2.via.ways[i3], vgraph);
-              if (!prev || curr !== prev) {
-                names.push(curr);
-              }
-            }
-            help.append("div").html(_t.html("restriction.help.via_names", {
-              via: placeholders.via,
-              viaNames: names.join(", ")
-            }));
+            selected = _t("intro.graph.name.12th-avenue");
+            other = _t("intro.graph.name.washington-street");
+            padding = 200 * Math.pow(2, context.map().zoom() - 18);
+            box = pad(twelfthAvenue, padding, context);
+            box.width /= 2;
           }
-          if (!indirect) {
-            help.append("div").html(_t.html("restriction.help.toggle", { turn: { html: nextText.trim() } }));
+          reveal(
+            box,
+            helpHtml(
+              "intro.lines.multi_select",
+              { selected, other1: other }
+            ) + " " + helpHtml(
+              "intro.lines.add_to_selection_" + (context.lastPointerType() === "mouse" ? "click" : "touch"),
+              { selected, other2: other }
+            ),
+            { duration: 0 }
+          );
+        });
+        context.on("enter.intro", function() {
+          continueTo(multiSelect2);
+        });
+        context.history().on("change.intro", function() {
+          if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+            return continueTo(rightClickIntersection);
           }
-          highlightPathsFrom(null);
-          var alongIDs = datum2.path.slice();
-          surface.selectAll(utilEntitySelector(alongIDs)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
-        } else {
-          highlightPathsFrom(null);
-          if (_fromWayID) {
-            help.append("div").html(_t.html("restriction.help.from_name", {
-              from: placeholders.from,
-              fromName: displayName(_fromWayID, vgraph)
-            }));
+        });
+      }, 600);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
+    }
+    function multiRightClick() {
+      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+        return continueTo(rightClickIntersection);
+      }
+      var padding = 200 * Math.pow(2, context.map().zoom() - 18);
+      var box = pad(twelfthAvenue, padding, context);
+      var rightClickString = helpHtml("intro.lines.multi_select_success") + helpHtml("intro.lines.multi_" + (context.lastPointerType() === "mouse" ? "rightclick" : "edit_menu_touch"));
+      reveal(box, rightClickString);
+      context.map().on("move.intro drawn.intro", function() {
+        var padding2 = 200 * Math.pow(2, context.map().zoom() - 18);
+        var box2 = pad(twelfthAvenue, padding2, context);
+        reveal(box2, rightClickString, { duration: 0 });
+      });
+      context.ui().editMenu().on("toggled.intro", function(open) {
+        if (!open) return;
+        timeout2(function() {
+          var ids = context.selectedIDs();
+          if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
+            var node = selectMenuItem(context, "delete").node();
+            if (!node) return;
+            continueTo(multiDelete);
+          } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
+            return continueTo(multiSelect2);
           } else {
-            help.append("div").html(_t.html("restriction.help.select_from", {
-              from: placeholders.from
-            }));
+            return continueTo(didSplit);
           }
+        }, 300);
+      });
+      context.history().on("change.intro", function() {
+        if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+          return continueTo(rightClickIntersection);
         }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.ui().editMenu().on("toggled.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
     }
-    function displayMaxDistance(maxDist) {
-      return (selection2) => {
-        var isImperial = !_mainLocalizer.usesMetric();
-        var opts;
-        if (isImperial) {
-          var distToFeet = {
-            20: 70,
-            25: 85,
-            30: 100,
-            35: 115,
-            40: 130,
-            45: 145,
-            50: 160
-          }[maxDist];
-          opts = { distance: _t("units.feet", { quantity: distToFeet }) };
+    function multiDelete() {
+      if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
+        return continueTo(rightClickIntersection);
+      }
+      var node = selectMenuItem(context, "delete").node();
+      if (!node) return continueTo(multiRightClick);
+      reveal(
+        ".edit-menu",
+        helpHtml("intro.lines.multi_delete"),
+        { padding: 50 }
+      );
+      context.map().on("move.intro drawn.intro", function() {
+        reveal(
+          ".edit-menu",
+          helpHtml("intro.lines.multi_delete"),
+          { duration: 0, padding: 50 }
+        );
+      });
+      context.on("exit.intro", function() {
+        if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
+          return continueTo(multiSelect2);
+        }
+      });
+      context.history().on("change.intro", function() {
+        if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
+          continueTo(retryDelete);
         } else {
-          opts = { distance: _t("units.meters", { quantity: maxDist }) };
+          continueTo(play);
         }
-        return selection2.html("").call(_t.append("restriction.controls.distance_up_to", opts));
-      };
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("exit.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
     }
-    function displayMaxVia(maxVia) {
-      return (selection2) => {
-        selection2 = selection2.html("");
-        return maxVia === 0 ? selection2.call(_t.append("restriction.controls.via_node_only")) : maxVia === 1 ? selection2.call(_t.append("restriction.controls.via_up_to_one")) : selection2.call(_t.append("restriction.controls.via_up_to_two"));
-      };
+    function retryDelete() {
+      context.enter(modeBrowse(context));
+      var padding = 200 * Math.pow(2, context.map().zoom() - 18);
+      var box = pad(twelfthAvenue, padding, context);
+      reveal(box, helpHtml("intro.lines.retry_delete"), {
+        buttonText: _t.html("intro.ok"),
+        buttonCallback: function() {
+          continueTo(multiSelect2);
+        }
+      });
+      function continueTo(nextStep) {
+        nextStep();
+      }
     }
-    function displayName(entityID, graph) {
-      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;
+    function play() {
+      dispatch14.call("done");
+      reveal(
+        ".ideditor",
+        helpHtml("intro.lines.play", { next: _t("intro.buildings.title") }),
+        {
+          tooltipBox: ".intro-nav-wrap .chapter-building",
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            reveal(".ideditor");
+          }
+        }
+      );
     }
-    restrictions.entityIDs = function(val) {
-      _intersection = null;
-      _fromWayID = null;
-      _oldTurns = null;
-      _vertexID = val[0];
-    };
-    restrictions.tags = function() {
+    chapter.enter = function() {
+      addLine();
     };
-    restrictions.focus = function() {
+    chapter.exit = function() {
+      timeouts.forEach(window.clearTimeout);
+      select_default2(window).on("pointerdown.intro mousedown.intro", null, true);
+      context.on("enter.intro exit.intro", null);
+      context.map().on("move.intro drawn.intro", null);
+      context.history().on("change.intro", null);
+      context.container().select(".inspector-wrap").on("wheel.intro", null);
+      context.container().select(".preset-list-button").on("click.intro", null);
     };
-    restrictions.off = function(selection2) {
-      if (!_initialized2)
-        return;
-      selection2.selectAll(".surface").call(breathe.off).on("click.restrictions", null).on("mouseover.restrictions", null);
-      select_default2(window).on("resize.restrictions", null);
+    chapter.restart = function() {
+      chapter.exit();
+      chapter.enter();
     };
-    return utilRebind(restrictions, dispatch10, "on");
+    return utilRebind(chapter, dispatch14, "on");
   }
-  uiFieldRestrictions.supportsMultiselection = false;
 
-  // modules/ui/fields/textarea.js
-  function uiFieldTextarea(field, context) {
-    var dispatch10 = dispatch_default("change");
-    var input = select_default2(null);
-    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);
-      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);
+  // modules/ui/intro/building.js
+  function uiIntroBuilding(context, reveal) {
+    var dispatch14 = dispatch_default("done");
+    var house = [-85.62815, 41.95638];
+    var tank = [-85.62732, 41.95347];
+    var buildingCatetory = _mainPresetIndex.item("category-building");
+    var housePreset = _mainPresetIndex.item("building/house");
+    var tankPreset = _mainPresetIndex.item("man_made/storage_tank");
+    var timeouts = [];
+    var _houseID = null;
+    var _tankID = null;
+    var chapter = {
+      title: "intro.buildings.title"
+    };
+    function timeout2(f2, t2) {
+      timeouts.push(window.setTimeout(f2, t2));
     }
-    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);
-      };
+    function eventCancel(d3_event) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
     }
-    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);
-    };
-    textarea.focus = function() {
-      input.node().focus();
-    };
-    return utilRebind(textarea, dispatch10, "on");
-  }
-
-  // modules/ui/fields/wikidata.js
-  function uiFieldWikidata(field, context) {
-    var wikidata = services.wikidata;
-    var dispatch10 = dispatch_default("change");
-    var _selection = select_default2(null);
-    var _searchInput = select_default2(null);
-    var _qid = null;
-    var _wikidataEntity = null;
-    var _wikiURL = "";
-    var _entityIDs = [];
-    var _wikipediaKey = field.keys && field.keys.find(function(key) {
-      return key.includes("wikipedia");
-    });
-    var _hintKey = field.key === "wikidata" ? "name" : field.key.split(":")[0];
-    var combobox = uiCombobox(context, "combo-" + field.safeid).caseSensitive(true).minItems(1);
-    function wiki(selection2) {
-      _selection = selection2;
-      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
-      var list = wrap2.selectAll("ul").data([0]);
-      list = list.enter().append("ul").attr("class", "rows").merge(list);
-      var searchRow = list.selectAll("li.wikidata-search").data([0]);
-      var searchRowEnter = searchRow.enter().append("li").attr("class", "wikidata-search");
-      searchRowEnter.append("input").attr("type", "text").attr("id", field.domId).style("flex", "1").call(utilNoAuto).on("focus", function() {
-        var node = select_default2(this).node();
-        node.setSelectionRange(0, node.value.length);
-      }).on("blur", function() {
-        setLabelForEntity();
-      }).call(combobox.fetcher(fetchWikidataItems));
-      combobox.on("accept", function(d) {
-        if (d) {
-          _qid = d.id;
-          change();
-        }
-      }).on("cancel", function() {
-        setLabelForEntity();
-      });
-      searchRowEnter.append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain: "wikidata.org" })).call(svgIcon("#iD-icon-out-link")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        if (_wikiURL)
-          window.open(_wikiURL, "_blank");
-      });
-      searchRow = searchRow.merge(searchRowEnter);
-      _searchInput = searchRow.select("input");
-      var wikidataProperties = ["description", "identifier"];
-      var items = list.selectAll("li.labeled-input").data(wikidataProperties);
-      var enter = items.enter().append("li").attr("class", function(d) {
-        return "labeled-input preset-wikidata-" + d;
-      });
-      enter.append("span").attr("class", "label").html(function(d) {
-        return _t.html("wikidata." + d);
-      });
-      enter.append("input").attr("type", "text").call(utilNoAuto).classed("disabled", "true").attr("readonly", "true");
-      enter.append("button").attr("class", "form-field-button").attr("title", _t("icons.copy")).call(svgIcon("#iD-operation-copy")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        select_default2(this.parentNode).select("input").node().select();
-        document.execCommand("copy");
-      });
+    function revealHouse(center, text, options2) {
+      var padding = 160 * Math.pow(2, context.map().zoom() - 20);
+      var box = pad(center, padding, context);
+      reveal(box, text, options2);
     }
-    function fetchWikidataItems(q, callback) {
-      if (!q && _hintKey) {
-        for (var i2 in _entityIDs) {
-          var entity = context.hasEntity(_entityIDs[i2]);
-          if (entity.tags[_hintKey]) {
-            q = entity.tags[_hintKey];
-            break;
-          }
-        }
+    function revealTank(center, text, options2) {
+      var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
+      var box = pad(center, padding, context);
+      reveal(box, text, options2);
+    }
+    function addHouse() {
+      context.enter(modeBrowse(context));
+      context.history().reset("initial");
+      _houseID = null;
+      var msec = transitionTime(house, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
       }
-      wikidata.itemsForSearchQuery(q, function(err, data) {
-        if (err)
-          return;
-        var result = data.map(function(item) {
-          return {
-            id: item.id,
-            value: item.display.label.value + " (" + item.id + ")",
-            display: (selection2) => selection2.append("span").attr("class", "localized-text").attr("lang", item.display.label.language).text(item.display.label.value),
-            title: item.display.description && item.display.description.value,
-            terms: item.aliases
-          };
+      context.map().centerZoomEase(house, 19, msec);
+      timeout2(function() {
+        var tooltip = reveal(
+          "button.add-area",
+          helpHtml("intro.buildings.add_building")
+        );
+        tooltip.selectAll(".popover-inner").insert("svg", "span").attr("class", "tooltip-illustration").append("use").attr("xlink:href", "#iD-graphic-buildings");
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "add-area") return;
+          continueTo(startHouse);
         });
-        if (callback)
-          callback(result);
-      });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        nextStep();
+      }
     }
-    function change() {
-      var syncTags = {};
-      syncTags[field.key] = _qid;
-      dispatch10.call("change", this, syncTags);
-      var initGraph = context.graph();
-      var initEntityIDs = _entityIDs;
-      wikidata.entityByQID(_qid, function(err, entity) {
-        if (err)
-          return;
-        if (context.graph() !== initGraph)
-          return;
-        if (!entity.sitelinks)
-          return;
-        var langs = wikidata.languagesToQuery();
-        ["labels", "descriptions"].forEach(function(key) {
-          if (!entity[key])
-            return;
-          var valueLangs = Object.keys(entity[key]);
-          if (valueLangs.length === 0)
-            return;
-          var valueLang = valueLangs[0];
-          if (langs.indexOf(valueLang) === -1) {
-            langs.push(valueLang);
-          }
+    function startHouse() {
+      if (context.mode().id !== "add-area") {
+        return continueTo(addHouse);
+      }
+      _houseID = null;
+      context.map().zoomEase(20, 500);
+      timeout2(function() {
+        var startString = helpHtml("intro.buildings.start_building") + helpHtml("intro.buildings.building_corner_" + (context.lastPointerType() === "mouse" ? "click" : "tap"));
+        revealHouse(house, startString);
+        context.map().on("move.intro drawn.intro", function() {
+          revealHouse(house, startString, { duration: 0 });
         });
-        var newWikipediaValue;
-        if (_wikipediaKey) {
-          var foundPreferred;
-          for (var i2 in langs) {
-            var lang = langs[i2];
-            var siteID = lang.replace("-", "_") + "wiki";
-            if (entity.sitelinks[siteID]) {
-              foundPreferred = true;
-              newWikipediaValue = lang + ":" + entity.sitelinks[siteID].title;
-              break;
-            }
-          }
-          if (!foundPreferred) {
-            var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function(site) {
-              return site.endsWith("wiki");
-            });
-            if (wikiSiteKeys.length === 0) {
-              newWikipediaValue = null;
-            } else {
-              var wikiLang = wikiSiteKeys[0].slice(0, -4).replace("_", "-");
-              var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
-              newWikipediaValue = wikiLang + ":" + wikiTitle;
-            }
-          }
-        }
-        if (newWikipediaValue) {
-          newWikipediaValue = context.cleanTagValue(newWikipediaValue);
-        }
-        if (typeof newWikipediaValue === "undefined")
-          return;
-        var actions = initEntityIDs.map(function(entityID) {
-          var entity2 = context.hasEntity(entityID);
-          if (!entity2)
-            return null;
-          var currTags = Object.assign({}, entity2.tags);
-          if (newWikipediaValue === null) {
-            if (!currTags[_wikipediaKey])
-              return null;
-            delete currTags[_wikipediaKey];
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "draw-area") return chapter.restart();
+          continueTo(continueHouse);
+        });
+      }, 550);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
+      }
+    }
+    function continueHouse() {
+      if (context.mode().id !== "draw-area") {
+        return continueTo(addHouse);
+      }
+      _houseID = null;
+      var continueString = helpHtml("intro.buildings.continue_building") + "{br}" + helpHtml("intro.areas.finish_area_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.buildings.finish_building");
+      revealHouse(house, continueString);
+      context.map().on("move.intro drawn.intro", function() {
+        revealHouse(house, continueString, { duration: 0 });
+      });
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "draw-area") {
+          return;
+        } else if (mode.id === "select") {
+          var graph = context.graph();
+          var way = context.entity(context.selectedIDs()[0]);
+          var nodes = graph.childNodes(way);
+          var points = utilArrayUniq(nodes).map(function(n3) {
+            return context.projection(n3.loc);
+          });
+          if (isMostlySquare(points)) {
+            _houseID = way.id;
+            return continueTo(chooseCategoryBuilding);
           } else {
-            currTags[_wikipediaKey] = newWikipediaValue;
+            return continueTo(retryHouse);
           }
-          return actionChangeTags(entityID, currTags);
-        }).filter(Boolean);
-        if (!actions.length)
-          return;
-        context.overwrite(
-          function actionUpdateWikipediaTags(graph) {
-            actions.forEach(function(action) {
-              graph = action(graph);
-            });
-            return graph;
-          },
-          context.history().undoAnnotation()
+        } else {
+          return chapter.restart();
+        }
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
+      }
+    }
+    function retryHouse() {
+      var onClick = function() {
+        continueTo(addHouse);
+      };
+      revealHouse(
+        house,
+        helpHtml("intro.buildings.retry_building"),
+        { buttonText: _t.html("intro.ok"), buttonCallback: onClick }
+      );
+      context.map().on("move.intro drawn.intro", function() {
+        revealHouse(
+          house,
+          helpHtml("intro.buildings.retry_building"),
+          { duration: 0, buttonText: _t.html("intro.ok"), buttonCallback: onClick }
         );
       });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        nextStep();
+      }
     }
-    function setLabelForEntity() {
-      var label = "";
-      if (_wikidataEntity) {
-        label = entityPropertyForDisplay(_wikidataEntity, "labels");
-        if (label.length === 0) {
-          label = _wikidataEntity.id.toString();
+    function chooseCategoryBuilding() {
+      if (!_houseID || !context.hasEntity(_houseID)) {
+        return addHouse();
+      }
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _houseID) {
+        context.enter(modeSelect(context, [_houseID]));
+      }
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      timeout2(function() {
+        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
+        var button = context.container().select(".preset-category-building .preset-list-button");
+        reveal(
+          button.node(),
+          helpHtml("intro.buildings.choose_category_building", { category: buildingCatetory.name() })
+        );
+        button.on("click.intro", function() {
+          button.on("click.intro", null);
+          continueTo(choosePresetHouse);
+        });
+      }, 400);
+      context.on("enter.intro", function(mode) {
+        if (!_houseID || !context.hasEntity(_houseID)) {
+          return continueTo(addHouse);
+        }
+        var ids2 = context.selectedIDs();
+        if (mode.id !== "select" || !ids2.length || ids2[0] !== _houseID) {
+          return continueTo(chooseCategoryBuilding);
         }
+      });
+      function continueTo(nextStep) {
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.container().select(".preset-list-button").on("click.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-      utilGetSetValue(_searchInput, label);
     }
-    wiki.tags = function(tags) {
-      var isMixed = Array.isArray(tags[field.key]);
-      _searchInput.attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : "").classed("mixed", isMixed);
-      _qid = typeof tags[field.key] === "string" && tags[field.key] || "";
-      if (!/^Q[0-9]*$/.test(_qid)) {
-        unrecognized();
-        return;
+    function choosePresetHouse() {
+      if (!_houseID || !context.hasEntity(_houseID)) {
+        return addHouse();
       }
-      _wikiURL = "https://wikidata.org/wiki/" + _qid;
-      wikidata.entityByQID(_qid, function(err, entity) {
-        if (err) {
-          unrecognized();
-          return;
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _houseID) {
+        context.enter(modeSelect(context, [_houseID]));
+      }
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      timeout2(function() {
+        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
+        var button = context.container().select(".preset-building-house .preset-list-button");
+        reveal(
+          button.node(),
+          helpHtml("intro.buildings.choose_preset_house", { preset: housePreset.name() }),
+          { duration: 300 }
+        );
+        button.on("click.intro", function() {
+          button.on("click.intro", null);
+          continueTo(closeEditorHouse);
+        });
+      }, 400);
+      context.on("enter.intro", function(mode) {
+        if (!_houseID || !context.hasEntity(_houseID)) {
+          return continueTo(addHouse);
         }
-        _wikidataEntity = entity;
-        setLabelForEntity();
-        var description = entityPropertyForDisplay(entity, "descriptions");
-        _selection.select("button.wiki-link").classed("disabled", false);
-        _selection.select(".preset-wikidata-description").style("display", function() {
-          return description.length > 0 ? "flex" : "none";
-        }).select("input").attr("value", description);
-        _selection.select(".preset-wikidata-identifier").style("display", function() {
-          return entity.id ? "flex" : "none";
-        }).select("input").attr("value", entity.id);
-      });
-      function unrecognized() {
-        _wikidataEntity = null;
-        setLabelForEntity();
-        _selection.select(".preset-wikidata-description").style("display", "none");
-        _selection.select(".preset-wikidata-identifier").style("display", "none");
-        _selection.select("button.wiki-link").classed("disabled", true);
-        if (_qid && _qid !== "") {
-          _wikiURL = "https://wikidata.org/wiki/Special:Search?search=" + _qid;
-        } else {
-          _wikiURL = "";
+        var ids2 = context.selectedIDs();
+        if (mode.id !== "select" || !ids2.length || ids2[0] !== _houseID) {
+          return continueTo(chooseCategoryBuilding);
         }
+      });
+      function continueTo(nextStep) {
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.container().select(".preset-list-button").on("click.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-    };
-    function entityPropertyForDisplay(wikidataEntity, propKey) {
-      if (!wikidataEntity[propKey])
-        return "";
-      var propObj = wikidataEntity[propKey];
-      var langKeys = Object.keys(propObj);
-      if (langKeys.length === 0)
-        return "";
-      var langs = wikidata.languagesToQuery();
-      for (var i2 in langs) {
-        var lang = langs[i2];
-        var valueObj = propObj[lang];
-        if (valueObj && valueObj.value && valueObj.value.length > 0)
-          return valueObj.value;
+    }
+    function closeEditorHouse() {
+      if (!_houseID || !context.hasEntity(_houseID)) {
+        return addHouse();
+      }
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _houseID) {
+        context.enter(modeSelect(context, [_houseID]));
+      }
+      context.history().checkpoint("hasHouse");
+      context.on("exit.intro", function() {
+        continueTo(rightClickHouse);
+      });
+      timeout2(function() {
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.buildings.close", { button: { html: icon("#iD-icon-close", "inline") } })
+        );
+      }, 500);
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
       }
-      return propObj[langKeys[0]].value;
     }
-    wiki.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return wiki;
-    };
-    wiki.focus = function() {
-      _searchInput.node().focus();
-    };
-    return utilRebind(wiki, dispatch10, "on");
-  }
-
-  // modules/ui/fields/wikipedia.js
-  function uiFieldWikipedia(field, context) {
-    const dispatch10 = dispatch_default("change");
-    const wikipedia = services.wikipedia;
-    const wikidata = services.wikidata;
-    let _langInput = select_default2(null);
-    let _titleInput = select_default2(null);
-    let _wikiURL = "";
-    let _entityIDs;
-    let _tags;
-    let _dataWikipedia = [];
-    _mainFileFetcher.get("wmf_sitematrix").then((d) => {
-      _dataWikipedia = d;
-      if (_tags)
-        updateForTags(_tags);
-    }).catch(() => {
-    });
-    const langCombo = uiCombobox(context, "wikipedia-lang").fetcher((value, callback) => {
-      const v = value.toLowerCase();
-      callback(
-        _dataWikipedia.filter((d) => {
-          return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
-        }).map((d) => ({ value: d[1] }))
-      );
-    });
-    const titleCombo = uiCombobox(context, "wikipedia-title").fetcher((value, callback) => {
-      if (!value) {
-        value = "";
-        for (let i2 in _entityIDs) {
-          let entity = context.hasEntity(_entityIDs[i2]);
-          if (entity.tags.name) {
-            value = entity.tags.name;
-            break;
-          }
-        }
+    function rightClickHouse() {
+      if (!_houseID) return chapter.restart();
+      context.enter(modeBrowse(context));
+      context.history().reset("hasHouse");
+      var zoom = context.map().zoom();
+      if (zoom < 20) {
+        zoom = 20;
       }
-      const searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
-      searchfn(language()[2], value, (query, data) => {
-        callback(data.map((d) => ({ value: d })));
+      context.map().centerZoomEase(house, zoom, 500);
+      context.on("enter.intro", function(mode) {
+        if (mode.id !== "select") return;
+        var ids = context.selectedIDs();
+        if (ids.length !== 1 || ids[0] !== _houseID) return;
+        timeout2(function() {
+          var node = selectMenuItem(context, "orthogonalize").node();
+          if (!node) return;
+          continueTo(clickSquare);
+        }, 50);
       });
-    });
-    function wiki(selection2) {
-      let wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
-      wrap2 = wrap2.enter().append("div").attr("class", `form-field-input-wrap form-field-input-${field.type}`).merge(wrap2);
-      let langContainer = wrap2.selectAll(".wiki-lang-container").data([0]);
-      langContainer = langContainer.enter().append("div").attr("class", "wiki-lang-container").merge(langContainer);
-      _langInput = langContainer.selectAll("input.wiki-lang").data([0]);
-      _langInput = _langInput.enter().append("input").attr("type", "text").attr("class", "wiki-lang").attr("placeholder", _t("translate.localized_translation_language")).call(utilNoAuto).call(langCombo).merge(_langInput);
-      _langInput.on("blur", changeLang).on("change", changeLang);
-      let titleContainer = wrap2.selectAll(".wiki-title-container").data([0]);
-      titleContainer = titleContainer.enter().append("div").attr("class", "wiki-title-container").merge(titleContainer);
-      _titleInput = titleContainer.selectAll("input.wiki-title").data([0]);
-      _titleInput = _titleInput.enter().append("input").attr("type", "text").attr("class", "wiki-title").attr("id", field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
-      _titleInput.on("blur", function() {
-        change(true);
-      }).on("change", function() {
-        change(false);
+      context.map().on("move.intro drawn.intro", function() {
+        var rightclickString = helpHtml("intro.buildings." + (context.lastPointerType() === "mouse" ? "rightclick_building" : "edit_menu_building_touch"));
+        revealHouse(house, rightclickString, { duration: 0 });
       });
-      let link2 = titleContainer.selectAll(".wiki-link").data([0]);
-      link2 = link2.enter().append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain: "wikipedia.org" })).call(svgIcon("#iD-icon-out-link")).merge(link2);
-      link2.on("click", (d3_event) => {
-        d3_event.preventDefault();
-        if (_wikiURL)
-          window.open(_wikiURL, "_blank");
+      context.history().on("change.intro", function() {
+        continueTo(rightClickHouse);
       });
-    }
-    function defaultLanguageInfo(skipEnglishFallback) {
-      const langCode = _mainLocalizer.languageCode().toLowerCase();
-      for (let i2 in _dataWikipedia) {
-        let d = _dataWikipedia[i2];
-        if (d[2] === langCode)
-          return d;
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-      return skipEnglishFallback ? ["", "", ""] : ["English", "English", "en"];
     }
-    function language(skipEnglishFallback) {
-      const value = utilGetSetValue(_langInput).toLowerCase();
-      for (let i2 in _dataWikipedia) {
-        let d = _dataWikipedia[i2];
-        if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value)
-          return d;
+    function clickSquare() {
+      if (!_houseID) return chapter.restart();
+      var entity = context.hasEntity(_houseID);
+      if (!entity) return continueTo(rightClickHouse);
+      var node = selectMenuItem(context, "orthogonalize").node();
+      if (!node) {
+        return continueTo(rightClickHouse);
       }
-      return defaultLanguageInfo(skipEnglishFallback);
-    }
-    function changeLang() {
-      utilGetSetValue(_langInput, language()[1]);
-      change(true);
-    }
-    function change(skipWikidata) {
-      let value = utilGetSetValue(_titleInput);
-      const m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
-      const langInfo = m && _dataWikipedia.find((d) => m[1] === d[2]);
-      let syncTags = {};
-      if (langInfo) {
-        const nativeLangName = langInfo[1];
-        value = decodeURIComponent(m[2]).replace(/_/g, " ");
-        if (m[3]) {
-          let anchor;
-          anchor = decodeURIComponent(m[3]);
-          value += "#" + anchor.replace(/_/g, " ");
+      var wasChanged = false;
+      reveal(
+        ".edit-menu",
+        helpHtml("intro.buildings.square_building"),
+        { padding: 50 }
+      );
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "browse") {
+          continueTo(rightClickHouse);
+        } else if (mode.id === "move" || mode.id === "rotate") {
+          continueTo(retryClickSquare);
         }
-        value = value.slice(0, 1).toUpperCase() + value.slice(1);
-        utilGetSetValue(_langInput, nativeLangName);
-        utilGetSetValue(_titleInput, value);
-      }
-      if (value) {
-        syncTags.wikipedia = context.cleanTagValue(language()[2] + ":" + value);
-      } else {
-        syncTags.wikipedia = void 0;
-      }
-      dispatch10.call("change", this, syncTags);
-      if (skipWikidata || !value || !language()[2])
-        return;
-      const initGraph = context.graph();
-      const initEntityIDs = _entityIDs;
-      wikidata.itemsByTitle(language()[2], value, (err, data) => {
-        if (err || !data || !Object.keys(data).length)
-          return;
-        if (context.graph() !== initGraph)
-          return;
-        const qids = Object.keys(data);
-        const value2 = qids && qids.find((id2) => id2.match(/^Q\d+$/));
-        let actions = initEntityIDs.map((entityID) => {
-          let entity = context.entity(entityID).tags;
-          let currTags = Object.assign({}, entity);
-          if (currTags.wikidata !== value2) {
-            currTags.wikidata = value2;
-            return actionChangeTags(entityID, currTags);
-          }
-          return null;
-        }).filter(Boolean);
-        if (!actions.length)
-          return;
-        context.overwrite(
-          function actionUpdateWikidataTags(graph) {
-            actions.forEach(function(action) {
-              graph = action(graph);
-            });
-            return graph;
-          },
-          context.history().undoAnnotation()
+      });
+      context.map().on("move.intro", function() {
+        var node2 = selectMenuItem(context, "orthogonalize").node();
+        if (!wasChanged && !node2) {
+          return continueTo(rightClickHouse);
+        }
+        reveal(
+          ".edit-menu",
+          helpHtml("intro.buildings.square_building"),
+          { duration: 0, padding: 50 }
         );
       });
-    }
-    wiki.tags = (tags) => {
-      _tags = tags;
-      updateForTags(tags);
-    };
-    function updateForTags(tags) {
-      const value = typeof tags[field.key] === "string" ? tags[field.key] : "";
-      const m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
-      const tagLang = m && m[1];
-      const tagArticleTitle = m && m[2];
-      let anchor = m && m[3];
-      const tagLangInfo = tagLang && _dataWikipedia.find((d) => tagLang === d[2]);
-      if (tagLangInfo) {
-        const nativeLangName = tagLangInfo[1];
-        utilGetSetValue(_langInput, nativeLangName);
-        utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? "#" + anchor : ""));
-        if (anchor) {
-          try {
-            anchor = encodeURIComponent(anchor.replace(/ /g, "_")).replace(/%/g, ".");
-          } catch (e) {
-            anchor = anchor.replace(/ /g, "_");
+      context.history().on("change.intro", function() {
+        wasChanged = true;
+        context.history().on("change.intro", null);
+        timeout2(function() {
+          if (context.history().undoAnnotation() === _t("operations.orthogonalize.annotation.feature", { n: 1 })) {
+            continueTo(doneSquare);
+          } else {
+            continueTo(retryClickSquare);
           }
-        }
-        _wikiURL = "https://" + tagLang + ".wikipedia.org/wiki/" + tagArticleTitle.replace(/ /g, "_") + (anchor ? "#" + anchor : "");
-      } else {
-        utilGetSetValue(_titleInput, value);
-        if (value && value !== "") {
-          utilGetSetValue(_langInput, "");
-          const defaultLangInfo = defaultLanguageInfo();
-          _wikiURL = `https://${defaultLangInfo[2]}.wikipedia.org/w/index.php?fulltext=1&search=${value}`;
-        } else {
-          const shownOrDefaultLangInfo = language(true);
-          utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
-          _wikiURL = "";
-        }
+        }, 500);
+      });
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.map().on("move.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
     }
-    wiki.entityIDs = (val) => {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return wiki;
-    };
-    wiki.focus = () => {
-      _titleInput.node().focus();
-    };
-    return utilRebind(wiki, dispatch10, "on");
-  }
-  uiFieldWikipedia.supportsMultiselection = false;
-
-  // modules/ui/fields/index.js
-  var uiFields = {
-    access: uiFieldAccess,
-    address: uiFieldAddress,
-    check: uiFieldCheck,
-    combo: uiFieldCombo,
-    cycleway: uiFieldCycleway,
-    defaultCheck: uiFieldCheck,
-    email: uiFieldText,
-    identifier: uiFieldText,
-    lanes: uiFieldLanes,
-    localized: uiFieldLocalized,
-    roadheight: uiFieldRoadheight,
-    roadspeed: uiFieldRoadspeed,
-    manyCombo: uiFieldCombo,
-    multiCombo: uiFieldCombo,
-    networkCombo: uiFieldCombo,
-    number: uiFieldText,
-    onewayCheck: uiFieldCheck,
-    radio: uiFieldRadio,
-    restrictions: uiFieldRestrictions,
-    semiCombo: uiFieldCombo,
-    structureRadio: uiFieldRadio,
-    tel: uiFieldText,
-    text: uiFieldText,
-    textarea: uiFieldTextarea,
-    typeCombo: uiFieldCombo,
-    url: uiFieldText,
-    wikidata: uiFieldWikidata,
-    wikipedia: uiFieldWikipedia
-  };
-
-  // modules/ui/field.js
-  function uiField(context, presetField2, entityIDs, options2) {
-    options2 = Object.assign({
-      show: true,
-      wrap: true,
-      remove: true,
-      revert: true,
-      info: true
-    }, options2);
-    var dispatch10 = dispatch_default("change", "revert");
-    var field = Object.assign({}, presetField2);
-    field.domId = utilUniqueDomId("form-field-" + field.safeid);
-    var _show = options2.show;
-    var _state = "";
-    var _tags = {};
-    var _entityExtent;
-    if (entityIDs && entityIDs.length) {
-      _entityExtent = entityIDs.reduce(function(extent, entityID) {
-        var entity = context.graph().entity(entityID);
-        return extent.extend(entity.extent(context.graph()));
-      }, geoExtent());
-    }
-    var _locked = false;
-    var _lockedTip = uiTooltip().title(() => _t.append("inspector.lock.suggestion", { label: field.title })).placement("bottom");
-    field.keys = field.keys || [field.key];
-    if (_show && !field.impl) {
-      createField();
-    }
-    function createField() {
-      field.impl = uiFields[field.type](field, context).on("change", function(t, onInput) {
-        dispatch10.call("change", field, t, onInput);
-      });
-      if (entityIDs) {
-        field.entityIDs = entityIDs;
-        if (field.impl.entityIDs) {
-          field.impl.entityIDs(entityIDs);
+    function retryClickSquare() {
+      context.enter(modeBrowse(context));
+      revealHouse(house, helpHtml("intro.buildings.retry_square"), {
+        buttonText: _t.html("intro.ok"),
+        buttonCallback: function() {
+          continueTo(rightClickHouse);
         }
+      });
+      function continueTo(nextStep) {
+        nextStep();
       }
     }
-    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 original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
-        });
+    function doneSquare() {
+      context.history().checkpoint("doneSquare");
+      revealHouse(house, helpHtml("intro.buildings.done_square"), {
+        buttonText: _t.html("intro.ok"),
+        buttonCallback: function() {
+          continueTo(addTank);
+        }
       });
+      function continueTo(nextStep) {
+        nextStep();
+      }
     }
-    function tagsContainFieldKey() {
-      return field.keys.some(function(key) {
-        if (field.type === "multiCombo") {
-          for (var tagKey in _tags) {
-            if (tagKey.indexOf(key) === 0) {
-              return true;
-            }
-          }
-          return false;
-        }
-        return _tags[key] !== void 0;
-      });
-    }
-    function revert(d3_event, d) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
-      if (!entityIDs || _locked)
-        return;
-      dispatch10.call("revert", d, d.keys);
-    }
-    function remove2(d3_event, d) {
-      d3_event.stopPropagation();
-      d3_event.preventDefault();
-      if (_locked)
-        return;
-      var t = {};
-      d.keys.forEach(function(key) {
-        t[key] = void 0;
-      });
-      dispatch10.call("change", d, t);
+    function addTank() {
+      context.enter(modeBrowse(context));
+      context.history().reset("doneSquare");
+      _tankID = null;
+      var msec = transitionTime(tank, context.map().center());
+      if (msec) {
+        reveal(null, null, { duration: 0 });
+      }
+      context.map().centerZoomEase(tank, 19.5, msec);
+      timeout2(function() {
+        reveal(
+          "button.add-area",
+          helpHtml("intro.buildings.add_tank")
+        );
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "add-area") return;
+          continueTo(startTank);
+        });
+      }, msec + 100);
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        nextStep();
+      }
     }
-    field.render = function(selection2) {
-      var container = selection2.selectAll(".form-field").data([field]);
-      var enter = container.enter().append("div").attr("class", function(d) {
-        return "form-field form-field-" + d.safeid;
-      }).classed("nowrap", !options2.wrap);
-      if (options2.wrap) {
-        var labelEnter = enter.append("label").attr("class", "field-label").attr("for", function(d) {
-          return d.domId;
+    function startTank() {
+      if (context.mode().id !== "add-area") {
+        return continueTo(addTank);
+      }
+      _tankID = null;
+      timeout2(function() {
+        var startString = helpHtml("intro.buildings.start_tank") + helpHtml("intro.buildings.tank_edge_" + (context.lastPointerType() === "mouse" ? "click" : "tap"));
+        revealTank(tank, startString);
+        context.map().on("move.intro drawn.intro", function() {
+          revealTank(tank, startString, { duration: 0 });
         });
-        var textEnter = labelEnter.append("span").attr("class", "label-text");
-        textEnter.append("span").attr("class", "label-textvalue").each(function(d) {
-          d.label()(select_default2(this));
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "draw-area") return chapter.restart();
+          continueTo(continueTank);
         });
-        textEnter.append("span").attr("class", "label-textannotation");
-        if (options2.remove) {
-          labelEnter.append("button").attr("class", "remove-icon").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
-        }
-        if (options2.revert) {
-          labelEnter.append("button").attr("class", "modified-icon").attr("title", _t("icons.undo")).call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo"));
-        }
+      }, 550);
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
       }
-      container = container.merge(enter);
-      container.select(".field-label > .remove-icon").on("click", remove2);
-      container.select(".field-label > .modified-icon").on("click", revert);
-      container.each(function(d) {
-        var selection3 = select_default2(this);
-        if (!d.impl) {
-          createField();
-        }
-        var reference, help;
-        if (options2.wrap && field.type === "restrictions") {
-          help = uiFieldHelp(context, "restrictions");
-        }
-        if (options2.wrap && options2.info) {
-          var referenceKey = d.key || "";
-          if (d.type === "multiCombo") {
-            referenceKey = referenceKey.replace(/:$/, "");
-          }
-          reference = uiTagReference(d.reference || { key: referenceKey }, context);
-          if (_state === "hover") {
-            reference.showing(false);
-          }
+    }
+    function continueTank() {
+      if (context.mode().id !== "draw-area") {
+        return continueTo(addTank);
+      }
+      _tankID = null;
+      var continueString = helpHtml("intro.buildings.continue_tank") + "{br}" + helpHtml("intro.areas.finish_area_" + (context.lastPointerType() === "mouse" ? "click" : "tap")) + helpHtml("intro.buildings.finish_tank");
+      revealTank(tank, continueString);
+      context.map().on("move.intro drawn.intro", function() {
+        revealTank(tank, continueString, { duration: 0 });
+      });
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "draw-area") {
+          return;
+        } else if (mode.id === "select") {
+          _tankID = context.selectedIDs()[0];
+          return continueTo(searchPresetTank);
+        } else {
+          return continueTo(addTank);
         }
-        selection3.call(d.impl);
-        if (help) {
-          selection3.call(help.body).select(".field-label").call(help.button);
+      });
+      function continueTo(nextStep) {
+        context.map().on("move.intro drawn.intro", null);
+        context.on("enter.intro", null);
+        nextStep();
+      }
+    }
+    function searchPresetTank() {
+      if (!_tankID || !context.hasEntity(_tankID)) {
+        return addTank();
+      }
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _tankID) {
+        context.enter(modeSelect(context, [_tankID]));
+      }
+      context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+      timeout2(function() {
+        context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
+        context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
+        reveal(
+          ".preset-search-input",
+          helpHtml("intro.buildings.search_tank", { preset: tankPreset.name() })
+        );
+      }, 400);
+      context.on("enter.intro", function(mode) {
+        if (!_tankID || !context.hasEntity(_tankID)) {
+          return continueTo(addTank);
         }
-        if (reference) {
-          selection3.call(reference.body).select(".field-label").call(reference.button);
+        var ids2 = context.selectedIDs();
+        if (mode.id !== "select" || !ids2.length || ids2[0] !== _tankID) {
+          context.enter(modeSelect(context, [_tankID]));
+          context.container().select(".inspector-wrap .panewrap").style("right", "-100%");
+          context.container().select(".inspector-wrap").on("wheel.intro", eventCancel);
+          context.container().select(".preset-search-input").on("keydown.intro", null).on("keyup.intro", checkPresetSearch);
+          reveal(
+            ".preset-search-input",
+            helpHtml("intro.buildings.search_tank", { preset: tankPreset.name() })
+          );
+          context.history().on("change.intro", null);
         }
-        d.impl.tags(_tags);
       });
-      container.classed("locked", _locked).classed("modified", isModified()).classed("present", tagsContainFieldKey());
-      var annotation = container.selectAll(".field-label .label-textannotation");
-      var icon2 = annotation.selectAll(".icon").data(_locked ? [0] : []);
-      icon2.exit().remove();
-      icon2.enter().append("svg").attr("class", "icon").append("use").attr("xlink:href", "#fas-lock");
-      container.call(_locked ? _lockedTip : _lockedTip.destroy);
-    };
-    field.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      return field;
-    };
-    field.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
-      _tags = val;
-      if (tagsContainFieldKey() && !_show) {
-        _show = true;
-        if (!field.impl) {
-          createField();
+      function checkPresetSearch() {
+        var first = context.container().select(".preset-list-item:first-child");
+        if (first.classed("preset-man_made-storage_tank")) {
+          reveal(
+            first.select(".preset-list-button").node(),
+            helpHtml("intro.buildings.choose_tank", { preset: tankPreset.name() }),
+            { duration: 300 }
+          );
+          context.container().select(".preset-search-input").on("keydown.intro", eventCancel, true).on("keyup.intro", null);
+          context.history().on("change.intro", function() {
+            continueTo(closeEditorTank);
+          });
         }
       }
-      return field;
-    };
-    field.locked = function(val) {
-      if (!arguments.length)
-        return _locked;
-      _locked = val;
-      return field;
-    };
-    field.show = function() {
-      _show = true;
-      if (!field.impl) {
-        createField();
+      function continueTo(nextStep) {
+        context.container().select(".inspector-wrap").on("wheel.intro", null);
+        context.on("enter.intro", null);
+        context.history().on("change.intro", null);
+        context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
+        nextStep();
       }
-      if (field.default && field.key && _tags[field.key] !== field.default) {
-        var t = {};
-        t[field.key] = field.default;
-        dispatch10.call("change", this, t);
+    }
+    function closeEditorTank() {
+      if (!_tankID || !context.hasEntity(_tankID)) {
+        return addTank();
       }
-    };
-    field.isShown = function() {
-      return _show;
-    };
-    field.isAllowed = function() {
-      if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false)
-        return false;
-      if (field.geometry && !entityIDs.every(function(entityID) {
-        return field.matchGeometry(context.graph().geometry(entityID));
-      }))
-        return false;
-      if (entityIDs && _entityExtent && field.locationSetID) {
-        var validLocations = _mainLocations.locationsAt(_entityExtent.center());
-        if (!validLocations[field.locationSetID])
-          return false;
+      var ids = context.selectedIDs();
+      if (context.mode().id !== "select" || !ids.length || ids[0] !== _tankID) {
+        context.enter(modeSelect(context, [_tankID]));
       }
-      var prerequisiteTag = field.prerequisiteTag;
-      if (entityIDs && !tagsContainFieldKey() && prerequisiteTag) {
-        if (!entityIDs.every(function(entityID) {
-          var entity = context.graph().entity(entityID);
-          if (prerequisiteTag.key) {
-            var value = entity.tags[prerequisiteTag.key];
-            if (!value)
-              return false;
-            if (prerequisiteTag.valueNot) {
-              return prerequisiteTag.valueNot !== value;
-            }
-            if (prerequisiteTag.value) {
-              return prerequisiteTag.value === value;
-            }
-          } else if (prerequisiteTag.keyNot) {
-            if (entity.tags[prerequisiteTag.keyNot])
-              return false;
-          }
-          return true;
-        }))
-          return false;
+      context.history().checkpoint("hasTank");
+      context.on("exit.intro", function() {
+        continueTo(rightClickTank);
+      });
+      timeout2(function() {
+        reveal(
+          ".entity-editor-pane",
+          helpHtml("intro.buildings.close", { button: { html: icon("#iD-icon-close", "inline") } })
+        );
+      }, 500);
+      function continueTo(nextStep) {
+        context.on("exit.intro", null);
+        nextStep();
       }
-      return true;
-    };
-    field.focus = function() {
-      if (field.impl) {
-        field.impl.focus();
+    }
+    function rightClickTank() {
+      if (!_tankID) return continueTo(addTank);
+      context.enter(modeBrowse(context));
+      context.history().reset("hasTank");
+      context.map().centerEase(tank, 500);
+      timeout2(function() {
+        context.on("enter.intro", function(mode) {
+          if (mode.id !== "select") return;
+          var ids = context.selectedIDs();
+          if (ids.length !== 1 || ids[0] !== _tankID) return;
+          timeout2(function() {
+            var node = selectMenuItem(context, "circularize").node();
+            if (!node) return;
+            continueTo(clickCircle);
+          }, 50);
+        });
+        var rightclickString = helpHtml("intro.buildings." + (context.lastPointerType() === "mouse" ? "rightclick_tank" : "edit_menu_tank_touch"));
+        revealTank(tank, rightclickString);
+        context.map().on("move.intro drawn.intro", function() {
+          revealTank(tank, rightclickString, { duration: 0 });
+        });
+        context.history().on("change.intro", function() {
+          continueTo(rightClickTank);
+        });
+      }, 600);
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.map().on("move.intro drawn.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
       }
-    };
-    return utilRebind(field, dispatch10, "on");
-  }
-
-  // modules/ui/form_fields.js
-  function uiFormFields(context) {
-    var moreCombo = uiCombobox(context, "more-fields").minItems(1);
-    var _fieldsArr = [];
-    var _lastPlaceholder = "";
-    var _state = "";
-    var _klass = "";
-    function formFields(selection2) {
-      var allowedFields = _fieldsArr.filter(function(field) {
-        return field.isAllowed();
-      });
-      var shown = allowedFields.filter(function(field) {
-        return field.isShown();
-      });
-      var notShown = allowedFields.filter(function(field) {
-        return !field.isShown();
-      });
-      var container = selection2.selectAll(".form-fields-container").data([0]);
-      container = container.enter().append("div").attr("class", "form-fields-container " + (_klass || "")).merge(container);
-      var fields = container.selectAll(".wrap-form-field").data(shown, function(d) {
-        return d.id + (d.entityIDs ? d.entityIDs.join() : "");
+    }
+    function clickCircle() {
+      if (!_tankID) return chapter.restart();
+      var entity = context.hasEntity(_tankID);
+      if (!entity) return continueTo(rightClickTank);
+      var node = selectMenuItem(context, "circularize").node();
+      if (!node) {
+        return continueTo(rightClickTank);
+      }
+      var wasChanged = false;
+      reveal(
+        ".edit-menu",
+        helpHtml("intro.buildings.circle_tank"),
+        { padding: 50 }
+      );
+      context.on("enter.intro", function(mode) {
+        if (mode.id === "browse") {
+          continueTo(rightClickTank);
+        } else if (mode.id === "move" || mode.id === "rotate") {
+          continueTo(retryClickCircle);
+        }
       });
-      fields.exit().remove();
-      var enter = fields.enter().append("div").attr("class", function(d) {
-        return "wrap-form-field wrap-form-field-" + d.safeid;
+      context.map().on("move.intro", function() {
+        var node2 = selectMenuItem(context, "circularize").node();
+        if (!wasChanged && !node2) {
+          return continueTo(rightClickTank);
+        }
+        reveal(
+          ".edit-menu",
+          helpHtml("intro.buildings.circle_tank"),
+          { duration: 0, padding: 50 }
+        );
       });
-      fields = fields.merge(enter);
-      fields.order().each(function(d) {
-        select_default2(this).call(d.render);
+      context.history().on("change.intro", function() {
+        wasChanged = true;
+        context.history().on("change.intro", null);
+        timeout2(function() {
+          if (context.history().undoAnnotation() === _t("operations.circularize.annotation.feature", { n: 1 })) {
+            continueTo(play);
+          } else {
+            continueTo(retryClickCircle);
+          }
+        }, 500);
       });
-      var titles = [];
-      var moreFields = notShown.map(function(field) {
-        var title = field.title();
-        titles.push(title);
-        var terms = field.terms();
-        if (field.key)
-          terms.push(field.key);
-        if (field.keys)
-          terms = terms.concat(field.keys);
-        return {
-          display: field.label(),
-          value: title,
-          title,
-          field,
-          terms
-        };
+      function continueTo(nextStep) {
+        context.on("enter.intro", null);
+        context.map().on("move.intro", null);
+        context.history().on("change.intro", null);
+        nextStep();
+      }
+    }
+    function retryClickCircle() {
+      context.enter(modeBrowse(context));
+      revealTank(tank, helpHtml("intro.buildings.retry_circle"), {
+        buttonText: _t.html("intro.ok"),
+        buttonCallback: function() {
+          continueTo(rightClickTank);
+        }
       });
-      var placeholder = titles.slice(0, 3).join(", ") + (titles.length > 3 ? "\u2026" : "");
-      var more = selection2.selectAll(".more-fields").data(_state === "hover" || moreFields.length === 0 ? [] : [0]);
-      more.exit().remove();
-      var moreEnter = more.enter().append("div").attr("class", "more-fields").append("label");
-      moreEnter.append("span").call(_t.append("inspector.add_fields"));
-      more = moreEnter.merge(more);
-      var input = more.selectAll(".value").data([0]);
-      input.exit().remove();
-      input = input.enter().append("input").attr("class", "value").attr("type", "text").attr("placeholder", placeholder).call(utilNoAuto).merge(input);
-      input.call(utilGetSetValue, "").call(
-        moreCombo.data(moreFields).on("accept", function(d) {
-          if (!d)
-            return;
-          var field = d.field;
-          field.show();
-          selection2.call(formFields);
-          field.focus();
-        })
-      );
-      if (_lastPlaceholder !== placeholder) {
-        input.attr("placeholder", placeholder);
-        _lastPlaceholder = placeholder;
+      function continueTo(nextStep) {
+        nextStep();
       }
     }
-    formFields.fieldsArr = function(val) {
-      if (!arguments.length)
-        return _fieldsArr;
-      _fieldsArr = val || [];
-      return formFields;
+    function play() {
+      dispatch14.call("done");
+      reveal(
+        ".ideditor",
+        helpHtml("intro.buildings.play", { next: _t("intro.startediting.title") }),
+        {
+          tooltipBox: ".intro-nav-wrap .chapter-startEditing",
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            reveal(".ideditor");
+          }
+        }
+      );
+    }
+    chapter.enter = function() {
+      addHouse();
     };
-    formFields.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      return formFields;
+    chapter.exit = function() {
+      timeouts.forEach(window.clearTimeout);
+      context.on("enter.intro exit.intro", null);
+      context.map().on("move.intro drawn.intro", null);
+      context.history().on("change.intro", null);
+      context.container().select(".inspector-wrap").on("wheel.intro", null);
+      context.container().select(".preset-search-input").on("keydown.intro keyup.intro", null);
+      context.container().select(".more-fields .combobox-input").on("click.intro", null);
     };
-    formFields.klass = function(val) {
-      if (!arguments.length)
-        return _klass;
-      _klass = val;
-      return formFields;
+    chapter.restart = function() {
+      chapter.exit();
+      chapter.enter();
     };
-    return formFields;
+    return utilRebind(chapter, dispatch14, "on");
   }
 
-  // modules/ui/changeset_editor.js
-  function uiChangesetEditor(context) {
-    var dispatch10 = dispatch_default("change");
-    var formFields = uiFormFields(context);
-    var commentCombo = uiCombobox(context, "comment").caseSensitive(true);
-    var _fieldsArr;
-    var _tags;
-    var _changesetID;
-    function changesetEditor(selection2) {
-      render(selection2);
+  // modules/ui/intro/start_editing.js
+  function uiIntroStartEditing(context, reveal) {
+    var dispatch14 = dispatch_default("done", "startEditing");
+    var modalSelection = select_default2(null);
+    var chapter = {
+      title: "intro.startediting.title"
+    };
+    function showHelp() {
+      reveal(
+        ".map-control.help-control",
+        helpHtml("intro.startediting.help"),
+        {
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            shortcuts();
+          }
+        }
+      );
     }
-    function render(selection2) {
-      var initial = false;
-      if (!_fieldsArr) {
-        initial = true;
-        var presets = _mainPresetIndex;
-        _fieldsArr = [
-          uiField(context, presets.field("comment"), null, { show: true, revert: false }),
-          uiField(context, presets.field("source"), null, { show: false, revert: false }),
-          uiField(context, presets.field("hashtags"), null, { show: false, revert: false })
-        ];
-        _fieldsArr.forEach(function(field) {
-          field.on("change", function(t, onInput) {
-            dispatch10.call("change", field, void 0, t, onInput);
-          });
-        });
-      }
-      _fieldsArr.forEach(function(field) {
-        field.tags(_tags);
-      });
-      selection2.call(formFields.fieldsArr(_fieldsArr));
-      if (initial) {
-        var commentField = selection2.select(".form-field-comment textarea");
-        var commentNode = commentField.node();
-        if (commentNode) {
-          commentNode.focus();
-          commentNode.select();
+    function shortcuts() {
+      reveal(
+        ".map-control.help-control",
+        helpHtml("intro.startediting.shortcuts"),
+        {
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            showSave();
+          }
         }
-        utilTriggerEvent(commentField, "blur");
-        var osm = context.connection();
-        if (osm) {
-          osm.userChangesets(function(err, changesets) {
-            if (err)
-              return;
-            var comments = changesets.map(function(changeset) {
-              var comment = changeset.tags.comment;
-              return comment ? { title: comment, value: comment } : null;
-            }).filter(Boolean);
-            commentField.call(
-              commentCombo.data(utilArrayUniqBy(comments, "title"))
-            );
-          });
+      );
+    }
+    function showSave() {
+      context.container().selectAll(".shaded").remove();
+      reveal(
+        ".top-toolbar button.save",
+        helpHtml("intro.startediting.save"),
+        {
+          buttonText: _t.html("intro.ok"),
+          buttonCallback: function() {
+            showStart();
+          }
         }
-      }
-      var hasGoogle = _tags.comment.match(/google/i);
-      var commentWarning = selection2.select(".form-field-comment").selectAll(".comment-warning").data(hasGoogle ? [0] : []);
-      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"));
-      commentEnter.transition().duration(200).style("opacity", 1);
+      );
     }
-    changesetEditor.tags = function(_) {
-      if (!arguments.length)
-        return _tags;
-      _tags = _;
-      return changesetEditor;
-    };
-    changesetEditor.changesetID = function(_) {
-      if (!arguments.length)
-        return _changesetID;
-      if (_changesetID === _)
-        return changesetEditor;
-      _changesetID = _;
-      _fieldsArr = null;
-      return changesetEditor;
-    };
-    return utilRebind(changesetEditor, dispatch10, "on");
-  }
-
-  // modules/ui/commit.js
-  var import_fast_deep_equal9 = __toESM(require_fast_deep_equal());
-
-  // modules/util/jxon.js
-  var JXON = new function() {
-    var sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
-    function parseText(sValue) {
-      if (rIsNull.test(sValue)) {
-        return null;
-      }
-      if (rIsBool.test(sValue)) {
-        return sValue.toLowerCase() === "true";
-      }
-      if (isFinite(sValue)) {
-        return parseFloat(sValue);
-      }
-      if (isFinite(Date.parse(sValue))) {
-        return new Date(sValue);
-      }
-      return sValue;
-    }
-    function EmptyTree() {
+    function showStart() {
+      context.container().selectAll(".shaded").remove();
+      modalSelection = uiModal(context.container());
+      modalSelection.select(".modal").attr("class", "modal-splash modal");
+      modalSelection.selectAll(".close").remove();
+      var startbutton = modalSelection.select(".content").attr("class", "fillL").append("button").attr("class", "modal-section huge-modal-button").on("click", function() {
+        modalSelection.remove();
+      });
+      startbutton.append("svg").attr("class", "illustration").append("use").attr("xlink:href", "#iD-logo-walkthrough");
+      startbutton.append("h2").call(_t.append("intro.startediting.start"));
+      dispatch14.call("startEditing");
     }
-    EmptyTree.prototype.toString = function() {
-      return "null";
+    chapter.enter = function() {
+      showHelp();
     };
-    EmptyTree.prototype.valueOf = function() {
-      return null;
+    chapter.exit = function() {
+      modalSelection.remove();
+      context.container().selectAll(".shaded").remove();
     };
-    function objectify(vValue) {
-      return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
-    }
-    function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
-      var nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(), bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
-      var sProp, vContent, nLength = 0, sCollectedTxt = "", vResult = bHighVerb ? {} : true;
-      if (bChildren) {
-        for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
-          oNode = oParentNode.childNodes.item(nItem);
-          if (oNode.nodeType === 4) {
-            sCollectedTxt += oNode.nodeValue;
-          } else if (oNode.nodeType === 3) {
-            sCollectedTxt += oNode.nodeValue.trim();
-          } else if (oNode.nodeType === 1 && !oNode.prefix) {
-            aCache.push(oNode);
+    return utilRebind(chapter, dispatch14, "on");
+  }
+
+  // modules/ui/intro/intro.js
+  var chapterUi = {
+    welcome: uiIntroWelcome,
+    navigation: uiIntroNavigation,
+    point: uiIntroPoint,
+    area: uiIntroArea,
+    line: uiIntroLine,
+    building: uiIntroBuilding,
+    startEditing: uiIntroStartEditing
+  };
+  var chapterFlow = [
+    "welcome",
+    "navigation",
+    "point",
+    "area",
+    "line",
+    "building",
+    "startEditing"
+  ];
+  function uiIntro(context) {
+    const INTRO_IMAGERY = "EsriWorldImageryClarity";
+    let _introGraph = {};
+    let _currChapter;
+    function intro(selection2) {
+      _mainFileFetcher.get("intro_graph").then((dataIntroGraph) => {
+        for (let id2 in dataIntroGraph) {
+          if (!_introGraph[id2]) {
+            _introGraph[id2] = osmEntity(localize(dataIntroGraph[id2]));
           }
         }
+        selection2.call(startIntro);
+      }).catch(function() {
+      });
+    }
+    function startIntro(selection2) {
+      context.enter(modeBrowse(context));
+      let osm = context.connection();
+      let history = context.history().toJSON();
+      let hash = window.location.hash;
+      let center = context.map().center();
+      let zoom = context.map().zoom();
+      let background = context.background().baseLayerSource();
+      let overlays = context.background().overlayLayerSources();
+      let opacity = context.container().selectAll(".main-map .layer-background").style("opacity");
+      let caches = osm && osm.caches();
+      let baseEntities = context.history().graph().base().entities;
+      context.ui().sidebar.expand();
+      context.container().selectAll("button.sidebar-toggle").classed("disabled", true);
+      context.inIntro(true);
+      if (osm) {
+        osm.toggle(false).reset();
       }
-      var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
-      if (!bHighVerb && (bChildren || bAttributes)) {
-        vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
-      }
-      for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
-        sProp = aCache[nElId].nodeName.toLowerCase();
-        vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
-        if (vResult.hasOwnProperty(sProp)) {
-          if (vResult[sProp].constructor !== Array) {
-            vResult[sProp] = [vResult[sProp]];
-          }
-          vResult[sProp].push(vContent);
-        } else {
-          vResult[sProp] = vContent;
-          nLength++;
-        }
+      context.history().reset();
+      context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
+      context.history().checkpoint("initial");
+      let imagery = context.background().findSource(INTRO_IMAGERY);
+      if (imagery) {
+        context.background().baseLayerSource(imagery);
+      } else {
+        context.background().bing();
       }
-      if (bAttributes) {
-        var nAttrLen = oParentNode.attributes.length, sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
-        for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
-          oAttrib = oParentNode.attributes.item(nAttrib);
-          oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
+      overlays.forEach((d2) => context.background().toggleOverlayLayer(d2));
+      let layers = context.layers();
+      layers.all().forEach((item) => {
+        if (typeof item.layer.enabled === "function") {
+          item.layer.enabled(item.id === "osm");
         }
-        if (bNesteAttr) {
-          if (bFreeze) {
-            Object.freeze(oAttrParent);
+      });
+      context.container().selectAll(".main-map .layer-background").style("opacity", 1);
+      let curtain = uiCurtain(context.container().node());
+      selection2.call(curtain);
+      corePreferences("walkthrough_started", "yes");
+      let storedProgress = corePreferences("walkthrough_progress") || "";
+      let progress = storedProgress.split(";").filter(Boolean);
+      let chapters = chapterFlow.map((chapter, i3) => {
+        let s2 = chapterUi[chapter](context, curtain.reveal).on("done", () => {
+          buttons.filter((d2) => d2.title === s2.title).classed("finished", true);
+          if (i3 < chapterFlow.length - 1) {
+            const next = chapterFlow[i3 + 1];
+            context.container().select("button.chapter-".concat(next)).classed("next", true);
           }
-          vResult[sAttributesProp] = oAttrParent;
-          nLength -= nAttrLen - 1;
+          progress.push(chapter);
+          corePreferences("walkthrough_progress", utilArrayUniq(progress).join(";"));
+        });
+        return s2;
+      });
+      chapters[chapters.length - 1].on("startEditing", () => {
+        progress.push("startEditing");
+        corePreferences("walkthrough_progress", utilArrayUniq(progress).join(";"));
+        let incomplete = utilArrayDifference(chapterFlow, progress);
+        if (!incomplete.length) {
+          corePreferences("walkthrough_completed", "yes");
         }
-      }
-      if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
-        vResult[sValueProp] = vBuiltVal;
-      } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
-        vResult = vBuiltVal;
-      }
-      if (bFreeze && (bHighVerb || nLength > 0)) {
-        Object.freeze(vResult);
-      }
-      aCache.length = nLevelStart;
-      return vResult;
-    }
-    function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
-      var vValue, oChild;
-      if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
-        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
-      } else if (oParentObj.constructor === Date) {
-        oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
-      }
-      for (var sName in oParentObj) {
-        vValue = oParentObj[sName];
-        if (isFinite(sName) || vValue instanceof Function) {
-          continue;
+        curtain.remove();
+        navwrap.remove();
+        context.container().selectAll(".main-map .layer-background").style("opacity", opacity);
+        context.container().selectAll("button.sidebar-toggle").classed("disabled", false);
+        if (osm) {
+          osm.toggle(true).reset().caches(caches);
         }
-        if (sName === sValueProp) {
-          if (vValue !== null && vValue !== true) {
-            oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
-          }
-        } else if (sName === sAttributesProp) {
-          for (var sAttrib in vValue) {
-            oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
-          }
-        } else if (sName.charAt(0) === sAttrPref) {
-          oParentEl.setAttribute(sName.slice(1), vValue);
-        } else if (vValue.constructor === Array) {
-          for (var nItem = 0; nItem < vValue.length; nItem++) {
-            oChild = oXMLDoc.createElement(sName);
-            loadObjTree(oXMLDoc, oChild, vValue[nItem]);
-            oParentEl.appendChild(oChild);
-          }
-        } else {
-          oChild = oXMLDoc.createElement(sName);
-          if (vValue instanceof Object) {
-            loadObjTree(oXMLDoc, oChild, vValue);
-          } else if (vValue !== null && vValue !== true) {
-            oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
-          }
-          oParentEl.appendChild(oChild);
+        context.history().reset().merge(Object.values(baseEntities));
+        context.background().baseLayerSource(background);
+        overlays.forEach((d2) => context.background().toggleOverlayLayer(d2));
+        if (history) {
+          context.history().fromJSON(history, false);
+        }
+        context.map().centerZoom(center, zoom);
+        window.location.replace(hash);
+        context.inIntro(false);
+      });
+      let navwrap = selection2.append("div").attr("class", "intro-nav-wrap fillD");
+      navwrap.append("svg").attr("class", "intro-nav-wrap-logo").append("use").attr("xlink:href", "#iD-logo-walkthrough");
+      let buttonwrap = navwrap.append("div").attr("class", "joined").selectAll("button.chapter");
+      let buttons = buttonwrap.data(chapters).enter().append("button").attr("class", (d2, i3) => "chapter chapter-".concat(chapterFlow[i3])).on("click", enterChapter);
+      buttons.append("span").html((d2) => _t.html(d2.title));
+      buttons.append("span").attr("class", "status").call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward", "inline"));
+      enterChapter(null, chapters[0]);
+      function enterChapter(d3_event, newChapter) {
+        if (_currChapter) {
+          _currChapter.exit();
         }
+        context.enter(modeBrowse(context));
+        _currChapter = newChapter;
+        _currChapter.enter();
+        buttons.classed("next", false).classed("active", (d2) => d2.title === _currChapter.title);
       }
     }
-    this.build = function(oXMLParent, nVerbosity, bFreeze, bNesteAttributes) {
-      var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : 1;
-      return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
-    };
-    this.unbuild = function(oObjTree) {
-      var oNewDoc = document.implementation.createDocument("", "", null);
-      loadObjTree(oNewDoc, oNewDoc, oObjTree);
-      return oNewDoc;
+    return intro;
+  }
+
+  // modules/ui/issues_info.js
+  function uiIssuesInfo(context) {
+    var warningsItem = {
+      id: "warnings",
+      count: 0,
+      iconID: "iD-icon-alert",
+      descriptionID: "issues.warnings_and_errors"
     };
-    this.stringify = function(oObjTree) {
-      return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
+    var resolvedItem = {
+      id: "resolved",
+      count: 0,
+      iconID: "iD-icon-apply",
+      descriptionID: "issues.user_resolved_issues"
     };
-  }();
-
-  // modules/ui/sections/changes.js
-  function uiSectionChanges(context) {
-    var _discardTags = {};
-    _mainFileFetcher.get("discarded").then(function(d) {
-      _discardTags = d;
-    }).catch(function() {
-    });
-    var section = uiSection("changes-list", context).label(function() {
-      var history = context.history();
-      var summary = history.difference().summary();
-      return _t.append("inspector.title_count", { title: _t("commit.changes"), count: summary.length });
-    }).disclosureContent(renderDisclosureContent);
-    function renderDisclosureContent(selection2) {
-      var history = context.history();
-      var summary = history.difference().summary();
-      var container = selection2.selectAll(".commit-section").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "commit-section");
-      containerEnter.append("ul").attr("class", "changeset-list");
-      container = containerEnter.merge(container);
-      var items = container.select("ul").selectAll("li").data(summary);
-      var itemsEnter = items.enter().append("li").attr("class", "change-item");
-      var buttons = itemsEnter.append("button").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
-      buttons.each(function(d) {
-        select_default2(this).call(svgIcon("#iD-icon-" + d.entity.geometry(d.graph), "pre-text " + d.changeType));
-      });
-      buttons.append("span").attr("class", "change-type").html(function(d) {
-        return _t.html("commit." + d.changeType) + " ";
-      });
-      buttons.append("strong").attr("class", "entity-type").text(function(d) {
-        var matched = _mainPresetIndex.match(d.entity, d.graph);
-        return matched && matched.name() || utilDisplayType(d.entity.id);
-      });
-      buttons.append("span").attr("class", "entity-name").text(function(d) {
-        var name = utilDisplayName(d.entity) || "", string = "";
-        if (name !== "") {
-          string += ":";
-        }
-        return string += " " + name;
+    function update(selection2) {
+      var shownItems = [];
+      var liveIssues = context.validator().getIssues({
+        what: corePreferences("validate-what") || "edited",
+        where: corePreferences("validate-where") || "all"
       });
-      items = itemsEnter.merge(items);
-      var changeset = new osmChangeset().update({ id: void 0 });
-      var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
-      delete changeset.id;
-      var data = JXON.stringify(changeset.osmChangeJXON(changes));
-      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
-      var fileName = "changes.osc";
-      var linkEnter = container.selectAll(".download-changes").data([0]).enter().append("a").attr("class", "download-changes");
-      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
-      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("commit.download_changes"));
-      function mouseover(d) {
-        if (d.entity) {
-          context.surface().selectAll(
-            utilEntityOrMemberSelector([d.entity.id], context.graph())
-          ).classed("hover", true);
-        }
-      }
-      function mouseout() {
-        context.surface().selectAll(".hover").classed("hover", false);
+      if (liveIssues.length) {
+        warningsItem.count = liveIssues.length;
+        shownItems.push(warningsItem);
       }
-      function click(d3_event, change) {
-        if (change.changeType !== "deleted") {
-          var entity = change.entity;
-          context.map().zoomToEase(entity);
-          context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
+      if (corePreferences("validate-what") === "all") {
+        var resolvedIssues = context.validator().getResolvedIssues();
+        if (resolvedIssues.length) {
+          resolvedItem.count = resolvedIssues.length;
+          shownItems.push(resolvedItem);
         }
       }
-    }
-    return section;
-  }
-
-  // modules/ui/commit_warnings.js
-  function uiCommitWarnings(context) {
-    function commitWarnings(selection2) {
-      var issuesBySeverity = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeDisabledRules: true });
-      for (var severity in issuesBySeverity) {
-        var issues = issuesBySeverity[severity];
-        if (severity !== "error") {
-          issues = issues.filter(function(issue) {
-            return issue.type !== "help_request";
-          });
-        }
-        var section = severity + "-section";
-        var issueItem = severity + "-item";
-        var container = selection2.selectAll("." + section).data(issues.length ? [0] : []);
-        container.exit().remove();
-        var containerEnter = container.enter().append("div").attr("class", "modal-section " + section + " fillL2");
-        containerEnter.append("h3").call(severity === "warning" ? _t.append("commit.warnings") : _t.append("commit.errors"));
-        containerEnter.append("ul").attr("class", "changeset-list");
-        container = containerEnter.merge(container);
-        var items = container.select("ul").selectAll("li").data(issues, function(d) {
-          return d.key;
-        });
-        items.exit().remove();
-        var itemsEnter = items.enter().append("li").attr("class", issueItem);
-        var buttons = itemsEnter.append("button").on("mouseover", function(d3_event, d) {
-          if (d.entityIds) {
-            context.surface().selectAll(
-              utilEntityOrMemberSelector(
-                d.entityIds,
-                context.graph()
-              )
-            ).classed("hover", true);
-          }
-        }).on("mouseout", function() {
-          context.surface().selectAll(".hover").classed("hover", false);
-        }).on("click", function(d3_event, d) {
-          context.validator().focusIssue(d);
-        });
-        buttons.call(svgIcon("#iD-icon-alert", "pre-text"));
-        buttons.append("strong").attr("class", "issue-message");
-        buttons.filter(function(d) {
-          return d.tooltip;
-        }).call(
-          uiTooltip().title(function(d) {
-            return d.tooltip;
-          }).placement("top")
-        );
-        items = itemsEnter.merge(items);
-        items.selectAll(".issue-message").text("").each(function(d) {
-          return d.message(context)(select_default2(this));
+      var chips = selection2.selectAll(".chip").data(shownItems, function(d2) {
+        return d2.id;
+      });
+      chips.exit().remove();
+      var enter = chips.enter().append("a").attr("class", function(d2) {
+        return "chip " + d2.id + "-count";
+      }).attr("href", "#").each(function(d2) {
+        var chipSelection = select_default2(this);
+        var tooltipBehavior = uiTooltip().placement("top").title(() => _t.append(d2.descriptionID));
+        chipSelection.call(tooltipBehavior).on("click", function(d3_event) {
+          d3_event.preventDefault();
+          tooltipBehavior.hide(select_default2(this));
+          context.ui().togglePanes(context.container().select(".map-panes .issues-pane"));
         });
-      }
+        chipSelection.call(svgIcon("#" + d2.iconID));
+      });
+      enter.append("span").attr("class", "count");
+      enter.merge(chips).selectAll("span.count").text(function(d2) {
+        return d2.count.toString();
+      });
     }
-    return commitWarnings;
+    return function(selection2) {
+      update(selection2);
+      context.validator().on("validated.infobox", function() {
+        update(selection2);
+      });
+    };
   }
 
-  // modules/ui/commit.js
-  var readOnlyTags = [
-    /^changesets_count$/,
-    /^created_by$/,
-    /^ideditor:/,
-    /^imagery_used$/,
-    /^host$/,
-    /^locale$/,
-    /^warnings:/,
-    /^resolved:/,
-    /^closed:note$/,
-    /^closed:keepright$/,
-    /^closed:improveosm:/,
-    /^closed:osmose:/
-  ];
-  var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
-  function uiCommit(context) {
-    var dispatch10 = dispatch_default("cancel");
-    var _userDetails2;
-    var _selection;
-    var changesetEditor = uiChangesetEditor(context).on("change", changeTags);
-    var rawTagEditor = uiSectionRawTagEditor("changeset-tag-editor", context).on("change", changeTags).readOnlyTags(readOnlyTags);
-    var commitChanges = uiSectionChanges(context);
-    var commitWarnings = uiCommitWarnings(context);
-    function commit(selection2) {
-      _selection = selection2;
-      if (!context.changeset)
-        initChangeset();
-      loadDerivedChangesetTags();
-      selection2.call(render);
+  // modules/renderer/background_source.js
+  var import_lodash4 = __toESM(require_lodash());
+
+  // modules/util/IntervalTasksQueue.js
+  var IntervalTasksQueue = class {
+    /**
+     * Interval in milliseconds inside which only 1 task can execute.
+     * e.g. if interval is 200ms, and 5 async tasks are unqueued,
+     * they will complete in ~1s if not cleared
+     * @param {number} intervalInMs
+     */
+    constructor(intervalInMs) {
+      this.intervalInMs = intervalInMs;
+      this.pendingHandles = [];
+      this.time = 0;
     }
-    function initChangeset() {
-      var commentDate = +corePreferences("commentDate") || 0;
-      var currDate = Date.now();
-      var cutoff = 2 * 86400 * 1e3;
-      if (commentDate > currDate || currDate - commentDate > cutoff) {
-        corePreferences("comment", null);
-        corePreferences("hashtags", null);
-        corePreferences("source", null);
-      }
-      if (context.defaultChangesetComment()) {
-        corePreferences("comment", context.defaultChangesetComment());
-        corePreferences("commentDate", Date.now());
+    enqueue(task) {
+      let taskTimeout = this.time;
+      this.time += this.intervalInMs;
+      this.pendingHandles.push(setTimeout(() => {
+        this.time -= this.intervalInMs;
+        task();
+      }, taskTimeout));
+    }
+    clear() {
+      this.pendingHandles.forEach((timeoutHandle) => {
+        clearTimeout(timeoutHandle);
+      });
+      this.pendingHandles = [];
+      this.time = 0;
+    }
+  };
+
+  // modules/renderer/background_source.js
+  var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
+  window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function() {
+    isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
+  });
+  function localeDateString(s2) {
+    if (!s2) return null;
+    var options2 = { day: "numeric", month: "short", year: "numeric" };
+    var d2 = new Date(s2);
+    if (isNaN(d2.getTime())) return null;
+    return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+  }
+  function vintageRange(vintage) {
+    var s2;
+    if (vintage.start || vintage.end) {
+      s2 = vintage.start || "?";
+      if (vintage.start !== vintage.end) {
+        s2 += " - " + (vintage.end || "?");
       }
-      if (context.defaultChangesetSource()) {
-        corePreferences("source", context.defaultChangesetSource());
-        corePreferences("commentDate", Date.now());
+    }
+    return s2;
+  }
+  function rendererBackgroundSource(data) {
+    var source = Object.assign({}, data);
+    var _offset = [0, 0];
+    var _name = source.name;
+    var _description = source.description;
+    var _best = !!source.best;
+    var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
+    source.tileSize = data.tileSize || 256;
+    source.zoomExtent = data.zoomExtent || [0, 22];
+    source.overzoom = data.overzoom !== false;
+    source.offset = function(val) {
+      if (!arguments.length) return _offset;
+      _offset = val;
+      return source;
+    };
+    source.nudge = function(val, zoomlevel) {
+      _offset[0] += val[0] / Math.pow(2, zoomlevel);
+      _offset[1] += val[1] / Math.pow(2, zoomlevel);
+      return source;
+    };
+    source.name = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      return _t("imagery." + id_safe + ".name", { default: (0, import_lodash4.escape)(_name) });
+    };
+    source.label = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      return _t.append("imagery." + id_safe + ".name", { default: (0, import_lodash4.escape)(_name) });
+    };
+    source.hasDescription = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      var descriptionText = _mainLocalizer.tInfo("imagery." + id_safe + ".description", { default: (0, import_lodash4.escape)(_description) }).text;
+      return descriptionText !== "";
+    };
+    source.description = function() {
+      var id_safe = source.id.replace(/\./g, "<TX_DOT>");
+      return _t.append("imagery." + id_safe + ".description", { default: (0, import_lodash4.escape)(_description) });
+    };
+    source.best = function() {
+      return _best;
+    };
+    source.area = function() {
+      if (!data.polygon) return Number.MAX_VALUE;
+      var area = area_default({ type: "MultiPolygon", coordinates: [data.polygon] });
+      return isNaN(area) ? 0 : area;
+    };
+    source.imageryUsed = function() {
+      return _name || source.id;
+    };
+    source.template = function(val) {
+      if (!arguments.length) return _template;
+      if (source.id === "custom" || source.id === "Bing") {
+        _template = val;
       }
-      if (context.defaultChangesetHashtags()) {
-        corePreferences("hashtags", context.defaultChangesetHashtags());
-        corePreferences("commentDate", Date.now());
+      return source;
+    };
+    source.url = function(coord2) {
+      var result = _template.replace(/#[\s\S]*/u, "");
+      if (result === "") return result;
+      if (!source.type || source.id === "custom") {
+        if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(result)) {
+          source.type = "wms";
+          source.projection = "EPSG:3857";
+        } else if (/\{(x|y)\}/.test(result)) {
+          source.type = "tms";
+        } else if (/\{u\}/.test(result)) {
+          source.type = "bing";
+        }
       }
-      var detected = utilDetect();
-      var tags = {
-        comment: corePreferences("comment") || "",
-        created_by: context.cleanTagValue("iD " + context.version),
-        host: context.cleanTagValue(detected.host),
-        locale: context.cleanTagValue(_mainLocalizer.localeCode())
-      };
-      findHashtags(tags, true);
-      var hashtags = corePreferences("hashtags");
-      if (hashtags) {
-        tags.hashtags = hashtags;
-      }
-      var source = corePreferences("source");
-      if (source) {
-        tags.source = source;
-      }
-      var photoOverlaysUsed = context.history().photoOverlaysUsed();
-      if (photoOverlaysUsed.length) {
-        var sources = (tags.source || "").split(";");
-        if (sources.indexOf("streetlevel imagery") === -1) {
-          sources.push("streetlevel imagery");
-        }
-        photoOverlaysUsed.forEach(function(photoOverlay) {
-          if (sources.indexOf(photoOverlay) === -1) {
-            sources.push(photoOverlay);
+      if (source.type === "wms") {
+        var tileToProjectedCoords = function(x2, y2, z2) {
+          var zoomSize = Math.pow(2, z2);
+          var lon = x2 / zoomSize * Math.PI * 2 - Math.PI;
+          var lat = Math.atan(Math.sinh(Math.PI * (1 - 2 * y2 / zoomSize)));
+          switch (source.projection) {
+            case "EPSG:4326":
+              return {
+                x: lon * 180 / Math.PI,
+                y: lat * 180 / Math.PI
+              };
+            default:
+              var mercCoords = mercatorRaw(lon, lat);
+              return {
+                x: 2003750834e-2 / Math.PI * mercCoords[0],
+                y: 2003750834e-2 / Math.PI * mercCoords[1]
+              };
+          }
+        };
+        var tileSize = source.tileSize;
+        var projection2 = source.projection;
+        var minXmaxY = tileToProjectedCoords(coord2[0], coord2[1], coord2[2]);
+        var maxXminY = tileToProjectedCoords(coord2[0] + 1, coord2[1] + 1, coord2[2]);
+        result = result.replace(/\{(\w+)\}/g, function(token, key) {
+          switch (key) {
+            case "width":
+            case "height":
+              return tileSize;
+            case "proj":
+              return projection2;
+            case "wkid":
+              return projection2.replace(/^EPSG:/, "");
+            case "bbox":
+              if (projection2 === "EPSG:4326" && // The CRS parameter implies version 1.3 (prior versions use SRS)
+              /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
+                return maxXminY.y + "," + minXmaxY.x + "," + minXmaxY.y + "," + maxXminY.x;
+              } else {
+                return minXmaxY.x + "," + maxXminY.y + "," + maxXminY.x + "," + minXmaxY.y;
+              }
+            case "w":
+              return minXmaxY.x;
+            case "s":
+              return maxXminY.y;
+            case "n":
+              return maxXminY.x;
+            case "e":
+              return minXmaxY.y;
+            default:
+              return token;
           }
         });
-        tags.source = context.cleanTagValue(sources.join(";"));
-      }
-      context.changeset = new osmChangeset({ tags });
-    }
-    function loadDerivedChangesetTags() {
-      var osm = context.connection();
-      if (!osm)
-        return;
-      var tags = Object.assign({}, context.changeset.tags);
-      var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(";"));
-      tags.imagery_used = imageryUsed || "None";
-      var osmClosed = osm.getClosedIDs();
-      var itemType;
-      if (osmClosed.length) {
-        tags["closed:note"] = context.cleanTagValue(osmClosed.join(";"));
+      } else if (source.type === "tms") {
+        result = result.replace("{x}", coord2[0]).replace("{y}", coord2[1]).replace(/\{[t-]y\}/, Math.pow(2, coord2[2]) - coord2[1] - 1).replace(/\{z(oom)?\}/, coord2[2]).replace(/\{@2x\}|\{r\}/, isRetina ? "@2x" : "");
+      } else if (source.type === "bing") {
+        result = result.replace("{u}", function() {
+          var u2 = "";
+          for (var zoom = coord2[2]; zoom > 0; zoom--) {
+            var b2 = 0;
+            var mask = 1 << zoom - 1;
+            if ((coord2[0] & mask) !== 0) b2++;
+            if ((coord2[1] & mask) !== 0) b2 += 2;
+            u2 += b2.toString();
+          }
+          return u2;
+        });
       }
-      if (services.keepRight) {
-        var krClosed = services.keepRight.getClosedIDs();
-        if (krClosed.length) {
-          tags["closed:keepright"] = context.cleanTagValue(krClosed.join(";"));
-        }
+      result = result.replace(/\{switch:([^}]+)\}/, function(s2, r2) {
+        var subdomains = r2.split(",");
+        return subdomains[(coord2[0] + coord2[1]) % subdomains.length];
+      });
+      return result;
+    };
+    source.validZoom = function(z2) {
+      return source.zoomExtent[0] <= z2 && (source.overzoom || source.zoomExtent[1] > z2);
+    };
+    source.isLocatorOverlay = function() {
+      return source.id === "mapbox_locator_overlay";
+    };
+    source.isHidden = function() {
+      return source.id === "DigitalGlobe-Premium-vintage" || source.id === "DigitalGlobe-Standard-vintage";
+    };
+    source.copyrightNotices = function() {
+    };
+    source.getMetadata = function(center, tileCoord, callback) {
+      var vintage = {
+        start: localeDateString(source.startDate),
+        end: localeDateString(source.endDate)
+      };
+      vintage.range = vintageRange(vintage);
+      var metadata = { vintage };
+      callback(null, metadata);
+    };
+    return source;
+  }
+  rendererBackgroundSource.Bing = function(data, dispatch14) {
+    data.template = "https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=1&pr=odbl&n=z";
+    var bing = rendererBackgroundSource(data);
+    var key = utilAesDecrypt("5c875730b09c6b422433e807e1ff060b6536c791dbfffcffc4c6b18a1bdba1f14593d151adb50e19e1be1ab19aef813bf135d0f103475e5c724dec94389e45d0");
+    const strictParam = "n";
+    var url = "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/AerialOSM?include=ImageryProviders&uriScheme=https&key=" + key;
+    var cache = {};
+    var inflight = {};
+    var providers = [];
+    var taskQueue = new IntervalTasksQueue(250);
+    var metadataLastZoom = -1;
+    json_default(url).then(function(json) {
+      let imageryResource = json.resourceSets[0].resources[0];
+      let template = imageryResource.imageUrl;
+      let subDomains = imageryResource.imageUrlSubdomains;
+      let subDomainNumbers = subDomains.map((subDomain) => {
+        return subDomain.substring(1);
+      }).join(",");
+      template = template.replace("{subdomain}", "t{switch:".concat(subDomainNumbers, "}")).replace("{quadkey}", "{u}");
+      if (!new URLSearchParams(template).has(strictParam)) {
+        template += "&".concat(strictParam, "=z");
       }
-      if (services.improveOSM) {
-        var iOsmClosed = services.improveOSM.getClosedCounts();
-        for (itemType in iOsmClosed) {
-          tags["closed:improveosm:" + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
-        }
+      bing.template(template);
+      providers = imageryResource.imageryProviders.map(function(provider) {
+        return {
+          attribution: provider.attribution,
+          areas: provider.coverageAreas.map(function(area) {
+            return {
+              zoom: [area.zoomMin, area.zoomMax],
+              extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
+            };
+          })
+        };
+      });
+      dispatch14.call("change");
+    }).catch(function() {
+    });
+    bing.copyrightNotices = function(zoom, extent) {
+      zoom = Math.min(zoom, 21);
+      return providers.filter(function(provider) {
+        return provider.areas.some(function(area) {
+          return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
+        });
+      }).map(function(provider) {
+        return provider.attribution;
+      }).join(", ");
+    };
+    bing.getMetadata = function(center, tileCoord, callback) {
+      var tileID = tileCoord.slice(0, 3).join("/");
+      var zoom = Math.min(tileCoord[2], 21);
+      var centerPoint = center[1] + "," + center[0];
+      var url2 = "https://dev.virtualearth.net/REST/v1/Imagery/BasicMetadata/AerialOSM/" + centerPoint + "?zl=" + zoom + "&key=" + key;
+      if (inflight[tileID]) return;
+      if (!cache[tileID]) {
+        cache[tileID] = {};
       }
-      if (services.osmose) {
-        var osmoseClosed = services.osmose.getClosedCounts();
-        for (itemType in osmoseClosed) {
-          tags["closed:osmose:" + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
-        }
+      if (cache[tileID] && cache[tileID].metadata) {
+        return callback(null, cache[tileID].metadata);
       }
-      for (var key in tags) {
-        if (key.match(/(^warnings:)|(^resolved:)/)) {
-          delete tags[key];
-        }
+      inflight[tileID] = true;
+      if (metadataLastZoom !== tileCoord[2]) {
+        metadataLastZoom = tileCoord[2];
+        taskQueue.clear();
       }
-      function addIssueCounts(issues, prefix) {
-        var issuesByType = utilArrayGroupBy(issues, "type");
-        for (var issueType in issuesByType) {
-          var issuesOfType = issuesByType[issueType];
-          if (issuesOfType[0].subtype) {
-            var issuesBySubtype = utilArrayGroupBy(issuesOfType, "subtype");
-            for (var issueSubtype in issuesBySubtype) {
-              var issuesOfSubtype = issuesBySubtype[issueSubtype];
-              tags[prefix + ":" + issueType + ":" + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
-            }
-          } else {
-            tags[prefix + ":" + issueType] = context.cleanTagValue(issuesOfType.length.toString());
+      taskQueue.enqueue(() => {
+        json_default(url2).then(function(result) {
+          delete inflight[tileID];
+          if (!result) {
+            throw new Error("Unknown Error");
           }
-        }
-      }
-      var warnings = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeIgnored: true, includeDisabledRules: true }).warning.filter(function(issue) {
-        return issue.type !== "help_request";
+          var vintage = {
+            start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
+            end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
+          };
+          vintage.range = vintageRange(vintage);
+          var metadata = { vintage };
+          cache[tileID].metadata = metadata;
+          if (callback) callback(null, metadata);
+        }).catch(function(err) {
+          delete inflight[tileID];
+          if (callback) callback(err.message);
+        });
       });
-      addIssueCounts(warnings, "warnings");
-      var resolvedIssues = context.validator().getResolvedIssues();
-      addIssueCounts(resolvedIssues, "resolved");
-      context.changeset = context.changeset.update({ tags });
+    };
+    bing.terms_url = "https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details";
+    return bing;
+  };
+  rendererBackgroundSource.Esri = function(data) {
+    if (data.template.match(/blankTile/) === null) {
+      data.template = data.template + "?blankTile=false";
     }
-    function render(selection2) {
-      var osm = context.connection();
-      if (!osm)
-        return;
-      var header = selection2.selectAll(".header").data([0]);
-      var headerTitle = header.enter().append("div").attr("class", "header fillL");
-      headerTitle.append("div").append("h2").call(_t.append("commit.title"));
-      headerTitle.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
-        dispatch10.call("cancel", this);
-      }).call(svgIcon("#iD-icon-close"));
-      var body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      var changesetSection = body.selectAll(".changeset-editor").data([0]);
-      changesetSection = changesetSection.enter().append("div").attr("class", "modal-section changeset-editor").merge(changesetSection);
-      changesetSection.call(
-        changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)
-      );
-      body.call(commitWarnings);
-      var saveSection = body.selectAll(".save-section").data([0]);
-      saveSection = saveSection.enter().append("div").attr("class", "modal-section save-section fillL").merge(saveSection);
-      var prose = saveSection.selectAll(".commit-info").data([0]);
-      if (prose.enter().size()) {
-        _userDetails2 = null;
-      }
-      prose = prose.enter().append("p").attr("class", "commit-info").call(_t.append("commit.upload_explanation")).merge(prose);
-      osm.userDetails(function(err, user) {
-        if (err)
-          return;
-        if (_userDetails2 === user)
-          return;
-        _userDetails2 = user;
-        var userLink = select_default2(document.createElement("div"));
-        if (user.image_url) {
-          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
+    var esri = rendererBackgroundSource(data);
+    var cache = {};
+    var inflight = {};
+    var _prevCenter;
+    esri.fetchTilemap = function(center) {
+      if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5e3) return;
+      _prevCenter = center;
+      var z2 = 20;
+      var dummyUrl = esri.url([1, 2, 3]);
+      var x2 = Math.floor((center[0] + 180) / 360 * Math.pow(2, z2));
+      var y2 = Math.floor((1 - Math.log(Math.tan(center[1] * Math.PI / 180) + 1 / Math.cos(center[1] * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, z2));
+      var tilemapUrl = dummyUrl.replace(/tile\/[0-9]+\/[0-9]+\/[0-9]+\?blankTile=false/, "tilemap") + "/" + z2 + "/" + y2 + "/" + x2 + "/8/8";
+      json_default(tilemapUrl).then(function(tilemap) {
+        if (!tilemap) {
+          throw new Error("Unknown Error");
         }
-        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
-        prose.html(_t.html("commit.upload_explanation_with_user", { user: { html: userLink.html() } }));
-      });
-      var requestReview = saveSection.selectAll(".request-review").data([0]);
-      var requestReviewEnter = requestReview.enter().append("div").attr("class", "request-review");
-      var requestReviewDomId = utilUniqueDomId("commit-input-request-review");
-      var labelEnter = requestReviewEnter.append("label").attr("for", requestReviewDomId);
-      if (!labelEnter.empty()) {
-        labelEnter.call(uiTooltip().title(() => _t.append("commit.request_review_info")).placement("top"));
-      }
-      labelEnter.append("input").attr("type", "checkbox").attr("id", requestReviewDomId);
-      labelEnter.append("span").call(_t.append("commit.request_review"));
-      requestReview = requestReview.merge(requestReviewEnter);
-      var requestReviewInput = requestReview.selectAll("input").property("checked", isReviewRequested(context.changeset.tags)).on("change", toggleRequestReview);
-      var buttonSection = saveSection.selectAll(".buttons").data([0]);
-      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons fillL");
-      buttonEnter.append("button").attr("class", "secondary-action button cancel-button").append("span").attr("class", "label").call(_t.append("commit.cancel"));
-      var uploadButton = buttonEnter.append("button").attr("class", "action button save-button");
-      uploadButton.append("span").attr("class", "label").call(_t.append("commit.save"));
-      var uploadBlockerTooltipText = getUploadBlockerMessage();
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.selectAll(".cancel-button").on("click.cancel", function() {
-        dispatch10.call("cancel", this);
-      });
-      buttonSection.selectAll(".save-button").classed("disabled", uploadBlockerTooltipText !== null).on("click.save", function() {
-        if (!select_default2(this).classed("disabled")) {
-          this.blur();
-          for (var key in context.changeset.tags) {
-            if (!key)
-              delete context.changeset.tags[key];
+        var hasTiles = true;
+        for (var i3 = 0; i3 < tilemap.data.length; i3++) {
+          if (!tilemap.data[i3]) {
+            hasTiles = false;
+            break;
           }
-          context.uploader().save(context.changeset);
         }
+        esri.zoomExtent[1] = hasTiles ? 22 : 19;
+      }).catch(function() {
       });
-      uiTooltip().destroyAny(buttonSection.selectAll(".save-button"));
-      if (uploadBlockerTooltipText) {
-        buttonSection.selectAll(".save-button").call(uiTooltip().title(() => uploadBlockerTooltipText).placement("top"));
+    };
+    esri.getMetadata = function(center, tileCoord, callback) {
+      if (esri.id !== "EsriWorldImagery") {
+        return callback(null, {});
       }
-      var tagSection = body.selectAll(".tag-section.raw-tag-editor").data([0]);
-      tagSection = tagSection.enter().append("div").attr("class", "modal-section tag-section raw-tag-editor").merge(tagSection);
-      tagSection.call(
-        rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
-      );
-      var changesSection = body.selectAll(".commit-changes-section").data([0]);
-      changesSection = changesSection.enter().append("div").attr("class", "modal-section commit-changes-section").merge(changesSection);
-      changesSection.call(commitChanges.render);
-      function toggleRequestReview() {
-        var rr = requestReviewInput.property("checked");
-        updateChangeset({ review_requested: rr ? "yes" : void 0 });
-        tagSection.call(
-          rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
-        );
+      var tileID = tileCoord.slice(0, 3).join("/");
+      var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
+      var centerPoint = center[0] + "," + center[1];
+      var unknown = _t("info_panels.background.unknown");
+      var vintage = {};
+      var metadata = {};
+      if (inflight[tileID]) return;
+      var url = "https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/4/query";
+      url += "?returnGeometry=false&geometry=" + centerPoint + "&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json";
+      if (!cache[tileID]) {
+        cache[tileID] = {};
       }
-    }
-    function getUploadBlockerMessage() {
-      var errors = context.validator().getIssuesBySeverity({ what: "edited", where: "all" }).error;
-      if (errors.length) {
-        return _t.append("commit.outstanding_errors_message", { count: errors.length });
-      } else {
-        var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
-        if (!hasChangesetComment) {
-          return _t.append("commit.comment_needed_message");
-        }
+      if (cache[tileID] && cache[tileID].metadata) {
+        return callback(null, cache[tileID].metadata);
       }
-      return null;
-    }
-    function changeTags(_, changed, onInput) {
-      if (changed.hasOwnProperty("comment")) {
-        if (changed.comment === void 0) {
-          changed.comment = "";
+      inflight[tileID] = true;
+      json_default(url).then(function(result) {
+        delete inflight[tileID];
+        result = result.features.map((f2) => f2.attributes).filter((a2) => a2.MinMapLevel <= zoom && a2.MaxMapLevel >= zoom)[0];
+        if (!result) {
+          throw new Error("Unknown Error");
+        } else if (result.features && result.features.length < 1) {
+          throw new Error("No Results");
+        } else if (result.error && result.error.message) {
+          throw new Error(result.error.message);
         }
-        if (!onInput) {
-          corePreferences("comment", changed.comment);
-          corePreferences("commentDate", Date.now());
+        var captureDate = localeDateString(result.SRC_DATE2);
+        vintage = {
+          start: captureDate,
+          end: captureDate,
+          range: captureDate
+        };
+        metadata = {
+          vintage,
+          source: clean2(result.NICE_NAME),
+          description: clean2(result.NICE_DESC),
+          resolution: clean2(+Number(result.SRC_RES).toFixed(4)),
+          accuracy: clean2(+Number(result.SRC_ACC).toFixed(4))
+        };
+        if (isFinite(metadata.resolution)) {
+          metadata.resolution += " m";
         }
-      }
-      if (changed.hasOwnProperty("source")) {
-        if (changed.source === void 0) {
-          corePreferences("source", null);
-        } else if (!onInput) {
-          corePreferences("source", changed.source);
-          corePreferences("commentDate", Date.now());
+        if (isFinite(metadata.accuracy)) {
+          metadata.accuracy += " m";
         }
+        cache[tileID].metadata = metadata;
+        if (callback) callback(null, metadata);
+      }).catch(function(err) {
+        delete inflight[tileID];
+        if (callback) callback(err.message);
+      });
+      function clean2(val) {
+        return String(val).trim() || unknown;
       }
-      updateChangeset(changed, onInput);
-      if (_selection) {
-        _selection.call(render);
+    };
+    return esri;
+  };
+  rendererBackgroundSource.None = function() {
+    var source = rendererBackgroundSource({ id: "none", template: "" });
+    source.name = function() {
+      return _t("background.none");
+    };
+    source.label = function() {
+      return _t.append("background.none");
+    };
+    source.imageryUsed = function() {
+      return null;
+    };
+    source.area = function() {
+      return -1;
+    };
+    return source;
+  };
+  rendererBackgroundSource.Custom = function(template) {
+    var source = rendererBackgroundSource({ id: "custom", template });
+    source.name = function() {
+      return _t("background.custom");
+    };
+    source.label = function() {
+      return _t.append("background.custom");
+    };
+    source.imageryUsed = function() {
+      var cleaned = source.template();
+      if (cleaned.indexOf("?") !== -1) {
+        var parts = cleaned.split("?", 2);
+        var qs = utilStringQs(parts[1]);
+        ["access_token", "connectId", "token", "Signature"].forEach(function(param) {
+          if (qs[param]) {
+            qs[param] = "{apikey}";
+          }
+        });
+        cleaned = parts[0] + "?" + utilQsString(qs, true);
       }
+      cleaned = cleaned.replace(/token\/(\w+)/, "token/{apikey}").replace(/key=(\w+)/, "key={apikey}");
+      return "Custom (" + cleaned + " )";
+    };
+    source.area = function() {
+      return -2;
+    };
+    return source;
+  };
+
+  // node_modules/@turf/helpers/dist/esm/index.js
+  var earthRadius = 63710088e-1;
+  var factors = {
+    centimeters: earthRadius * 100,
+    centimetres: earthRadius * 100,
+    degrees: 360 / (2 * Math.PI),
+    feet: earthRadius * 3.28084,
+    inches: earthRadius * 39.37,
+    kilometers: earthRadius / 1e3,
+    kilometres: earthRadius / 1e3,
+    meters: earthRadius,
+    metres: earthRadius,
+    miles: earthRadius / 1609.344,
+    millimeters: earthRadius * 1e3,
+    millimetres: earthRadius * 1e3,
+    nauticalmiles: earthRadius / 1852,
+    radians: 1,
+    yards: earthRadius * 1.0936
+  };
+  function feature2(geom, properties, options2 = {}) {
+    const feat = { type: "Feature" };
+    if (options2.id === 0 || options2.id) {
+      feat.id = options2.id;
     }
-    function findHashtags(tags, commentOnly) {
-      var detectedHashtags = commentHashtags();
-      if (detectedHashtags.length) {
-        corePreferences("hashtags", null);
+    if (options2.bbox) {
+      feat.bbox = options2.bbox;
+    }
+    feat.properties = properties || {};
+    feat.geometry = geom;
+    return feat;
+  }
+  function polygon(coordinates, properties, options2 = {}) {
+    for (const ring of coordinates) {
+      if (ring.length < 4) {
+        throw new Error(
+          "Each LinearRing of a Polygon must have 4 or more Positions."
+        );
       }
-      if (!detectedHashtags.length || !commentOnly) {
-        detectedHashtags = detectedHashtags.concat(hashtagHashtags());
+      if (ring[ring.length - 1].length !== ring[0].length) {
+        throw new Error("First and last Position are not equivalent.");
       }
-      var allLowerCase = /* @__PURE__ */ new Set();
-      return detectedHashtags.filter(function(hashtag) {
-        var lowerCase = hashtag.toLowerCase();
-        if (!allLowerCase.has(lowerCase)) {
-          allLowerCase.add(lowerCase);
-          return true;
+      for (let j2 = 0; j2 < ring[ring.length - 1].length; j2++) {
+        if (ring[ring.length - 1][j2] !== ring[0][j2]) {
+          throw new Error("First and last Position are not equivalent.");
         }
-        return false;
-      });
-      function commentHashtags() {
-        var matches = (tags.comment || "").replace(/http\S*/g, "").match(hashtagRegex);
-        return matches || [];
-      }
-      function hashtagHashtags() {
-        var matches = (tags.hashtags || "").split(/[,;\s]+/).map(function(s) {
-          if (s[0] !== "#") {
-            s = "#" + s;
-          }
-          var matched = s.match(hashtagRegex);
-          return matched && matched[0];
-        }).filter(Boolean);
-        return matches || [];
       }
     }
-    function isReviewRequested(tags) {
-      var rr = tags.review_requested;
-      if (rr === void 0)
-        return false;
-      rr = rr.trim().toLowerCase();
-      return !(rr === "" || rr === "no");
+    const geom = {
+      type: "Polygon",
+      coordinates
+    };
+    return feature2(geom, properties, options2);
+  }
+  function lineString(coordinates, properties, options2 = {}) {
+    if (coordinates.length < 2) {
+      throw new Error("coordinates must be an array of two or more positions");
     }
-    function updateChangeset(changed, onInput) {
-      var tags = Object.assign({}, context.changeset.tags);
-      Object.keys(changed).forEach(function(k) {
-        var v = changed[k];
-        k = context.cleanTagKey(k);
-        if (readOnlyTags.indexOf(k) !== -1)
-          return;
-        if (v === void 0) {
-          delete tags[k];
-        } else if (onInput) {
-          tags[k] = v;
-        } else {
-          tags[k] = context.cleanTagValue(v);
-        }
-      });
-      if (!onInput) {
-        var commentOnly = changed.hasOwnProperty("comment") && changed.comment !== "";
-        var arr = findHashtags(tags, commentOnly);
-        if (arr.length) {
-          tags.hashtags = context.cleanTagValue(arr.join(";"));
-          corePreferences("hashtags", tags.hashtags);
-        } else {
-          delete tags.hashtags;
-          corePreferences("hashtags", null);
-        }
-      }
-      if (_userDetails2 && _userDetails2.changesets_count !== void 0) {
-        var changesetsCount = parseInt(_userDetails2.changesets_count, 10) + 1;
-        tags.changesets_count = String(changesetsCount);
-        if (changesetsCount <= 100) {
-          var s;
-          s = corePreferences("walkthrough_completed");
-          if (s) {
-            tags["ideditor:walkthrough_completed"] = s;
-          }
-          s = corePreferences("walkthrough_progress");
-          if (s) {
-            tags["ideditor:walkthrough_progress"] = s;
-          }
-          s = corePreferences("walkthrough_started");
-          if (s) {
-            tags["ideditor:walkthrough_started"] = s;
-          }
-        }
-      } else {
-        delete tags.changesets_count;
-      }
-      if (!(0, import_fast_deep_equal9.default)(context.changeset.tags, tags)) {
-        context.changeset = context.changeset.update({ tags });
-      }
-    }
-    commit.reset = function() {
-      context.changeset = null;
+    const geom = {
+      type: "LineString",
+      coordinates
     };
-    return utilRebind(commit, dispatch10, "on");
+    return feature2(geom, properties, options2);
   }
-
-  // modules/ui/confirm.js
-  function uiConfirm(selection2) {
-    var modalSelection = uiModal(selection2);
-    modalSelection.select(".modal").classed("modal-alert", true);
-    var section = modalSelection.select(".content");
-    section.append("div").attr("class", "modal-section header");
-    section.append("div").attr("class", "modal-section message-text");
-    var buttons = section.append("div").attr("class", "modal-section buttons cf");
-    modalSelection.okButton = function() {
-      buttons.append("button").attr("class", "button ok-button action").on("click.confirm", function() {
-        modalSelection.remove();
-      }).call(_t.append("confirm.okay")).node().focus();
-      return modalSelection;
+  function multiLineString(coordinates, properties, options2 = {}) {
+    const geom = {
+      type: "MultiLineString",
+      coordinates
     };
-    return modalSelection;
+    return feature2(geom, properties, options2);
+  }
+  function multiPolygon(coordinates, properties, options2 = {}) {
+    const geom = {
+      type: "MultiPolygon",
+      coordinates
+    };
+    return feature2(geom, properties, options2);
   }
 
-  // modules/ui/conflicts.js
-  function uiConflicts(context) {
-    var dispatch10 = dispatch_default("cancel", "save");
-    var keybinding = utilKeybinding("conflicts");
-    var _origChanges;
-    var _conflictList;
-    var _shownConflictIndex;
-    function keybindingOn() {
-      select_default2(document).call(keybinding.on("\u238B", cancel, true));
-    }
-    function keybindingOff() {
-      select_default2(document).call(keybinding.unbind);
-    }
-    function tryAgain() {
-      keybindingOff();
-      dispatch10.call("save");
-    }
-    function cancel() {
-      keybindingOff();
-      dispatch10.call("cancel");
+  // node_modules/@turf/invariant/dist/esm/index.js
+  function getGeom(geojson) {
+    if (geojson.type === "Feature") {
+      return geojson.geometry;
     }
-    function conflicts(selection2) {
-      keybindingOn();
-      var headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "fr").attr("title", _t("icons.close")).on("click", cancel).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("save.conflict.header"));
-      var bodyEnter = selection2.selectAll(".body").data([0]).enter().append("div").attr("class", "body fillL");
-      var conflictsHelpEnter = bodyEnter.append("div").attr("class", "conflicts-help").call(_t.append("save.conflict.help"));
-      var changeset = new osmChangeset();
-      delete changeset.id;
-      var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
-      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
-      var fileName = "changes.osc";
-      var linkEnter = conflictsHelpEnter.selectAll(".download-changes").append("a").attr("class", "download-changes");
-      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
-      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("save.conflict.download_changes"));
-      bodyEnter.append("div").attr("class", "conflict-container fillL3").call(showConflict, 0);
-      bodyEnter.append("div").attr("class", "conflicts-done").attr("opacity", 0).style("display", "none").call(_t.append("save.conflict.done"));
-      var buttonsEnter = bodyEnter.append("div").attr("class", "buttons col12 joined conflicts-buttons");
-      buttonsEnter.append("button").attr("disabled", _conflictList.length > 1).attr("class", "action conflicts-button col6").call(_t.append("save.title")).on("click.try_again", tryAgain);
-      buttonsEnter.append("button").attr("class", "secondary-action conflicts-button col6").call(_t.append("confirm.cancel")).on("click.cancel", cancel);
+    return geojson;
+  }
+
+  // node_modules/@turf/bbox-clip/dist/esm/index.js
+  function lineclip(points, bbox2, result) {
+    var len = points.length, codeA = bitCode(points[0], bbox2), part = [], i3, codeB, lastCode;
+    let a2;
+    let b2;
+    if (!result)
+      result = [];
+    for (i3 = 1; i3 < len; i3++) {
+      a2 = points[i3 - 1];
+      b2 = points[i3];
+      codeB = lastCode = bitCode(b2, bbox2);
+      while (true) {
+        if (!(codeA | codeB)) {
+          part.push(a2);
+          if (codeB !== lastCode) {
+            part.push(b2);
+            if (i3 < len - 1) {
+              result.push(part);
+              part = [];
+            }
+          } else if (i3 === len - 1) {
+            part.push(b2);
+          }
+          break;
+        } else if (codeA & codeB) {
+          break;
+        } else if (codeA) {
+          a2 = intersect(a2, b2, codeA, bbox2);
+          codeA = bitCode(a2, bbox2);
+        } else {
+          b2 = intersect(a2, b2, codeB, bbox2);
+          codeB = bitCode(b2, bbox2);
+        }
+      }
+      codeA = lastCode;
     }
-    function showConflict(selection2, index) {
-      index = utilWrap(index, _conflictList.length);
-      _shownConflictIndex = index;
-      var parent = select_default2(selection2.node().parentNode);
-      if (index === _conflictList.length - 1) {
-        window.setTimeout(function() {
-          parent.select(".conflicts-button").attr("disabled", null);
-          parent.select(".conflicts-done").transition().attr("opacity", 1).style("display", "block");
-        }, 250);
+    if (part.length)
+      result.push(part);
+    return result;
+  }
+  function polygonclip(points, bbox2) {
+    var result, edge, prev, prevInside, i3, p2, inside;
+    for (edge = 1; edge <= 8; edge *= 2) {
+      result = [];
+      prev = points[points.length - 1];
+      prevInside = !(bitCode(prev, bbox2) & edge);
+      for (i3 = 0; i3 < points.length; i3++) {
+        p2 = points[i3];
+        inside = !(bitCode(p2, bbox2) & edge);
+        if (inside !== prevInside)
+          result.push(intersect(prev, p2, edge, bbox2));
+        if (inside)
+          result.push(p2);
+        prev = p2;
+        prevInside = inside;
       }
-      var conflict = selection2.selectAll(".conflict").data([_conflictList[index]]);
-      conflict.exit().remove();
-      var conflictEnter = conflict.enter().append("div").attr("class", "conflict");
-      conflictEnter.append("h4").attr("class", "conflict-count").call(_t.append("save.conflict.count", { num: index + 1, total: _conflictList.length }));
-      conflictEnter.append("a").attr("class", "conflict-description").attr("href", "#").text(function(d) {
-        return d.name;
-      }).on("click", function(d3_event, d) {
-        d3_event.preventDefault();
-        zoomToEntity(d.id);
-      });
-      var details = conflictEnter.append("div").attr("class", "conflict-detail-container");
-      details.append("ul").attr("class", "conflict-detail-list").selectAll("li").data(function(d) {
-        return d.details || [];
-      }).enter().append("li").attr("class", "conflict-detail-item").html(function(d) {
-        return d;
-      });
-      details.append("div").attr("class", "conflict-choices").call(addChoices);
-      details.append("div").attr("class", "conflict-nav-buttons joined cf").selectAll("button").data(["previous", "next"]).enter().append("button").attr("class", "conflict-nav-button action col6").attr("disabled", function(d, i2) {
-        return i2 === 0 && index === 0 || i2 === 1 && index === _conflictList.length - 1 || null;
-      }).on("click", function(d3_event, d) {
-        d3_event.preventDefault();
-        var container = parent.selectAll(".conflict-container");
-        var sign2 = d === "previous" ? -1 : 1;
-        container.selectAll(".conflict").remove();
-        container.call(showConflict, index + sign2);
-      }).call(function(d) {
-        _t.append("save.conflict." + d)(select_default2(this));
-      });
+      points = result;
+      if (!points.length)
+        break;
     }
-    function addChoices(selection2) {
-      var choices = selection2.append("ul").attr("class", "layer-list").selectAll("li").data(function(d) {
-        return d.choices || [];
-      });
-      var choicesEnter = choices.enter().append("li").attr("class", "layer");
-      var labelEnter = choicesEnter.append("label");
-      labelEnter.append("input").attr("type", "radio").attr("name", function(d) {
-        return d.id;
-      }).on("change", function(d3_event, d) {
-        var ul = this.parentNode.parentNode.parentNode;
-        ul.__data__.chosen = d.id;
-        choose(d3_event, ul, d);
-      });
-      labelEnter.append("span").text(function(d) {
-        return d.text;
-      });
-      choicesEnter.merge(choices).each(function(d) {
-        var ul = this.parentNode;
-        if (ul.__data__.chosen === d.id) {
-          choose(null, ul, d);
+    return result;
+  }
+  function intersect(a2, b2, edge, bbox2) {
+    return edge & 8 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[3] - a2[1]) / (b2[1] - a2[1]), bbox2[3]] : edge & 4 ? [a2[0] + (b2[0] - a2[0]) * (bbox2[1] - a2[1]) / (b2[1] - a2[1]), bbox2[1]] : edge & 2 ? [bbox2[2], a2[1] + (b2[1] - a2[1]) * (bbox2[2] - a2[0]) / (b2[0] - a2[0])] : edge & 1 ? [bbox2[0], a2[1] + (b2[1] - a2[1]) * (bbox2[0] - a2[0]) / (b2[0] - a2[0])] : null;
+  }
+  function bitCode(p2, bbox2) {
+    var code = 0;
+    if (p2[0] < bbox2[0])
+      code |= 1;
+    else if (p2[0] > bbox2[2])
+      code |= 2;
+    if (p2[1] < bbox2[1])
+      code |= 4;
+    else if (p2[1] > bbox2[3])
+      code |= 8;
+    return code;
+  }
+  function bboxClip(feature3, bbox2) {
+    const geom = getGeom(feature3);
+    const type2 = geom.type;
+    const properties = feature3.type === "Feature" ? feature3.properties : {};
+    let coords = geom.coordinates;
+    switch (type2) {
+      case "LineString":
+      case "MultiLineString": {
+        const lines = [];
+        if (type2 === "LineString") {
+          coords = [coords];
         }
-      });
+        coords.forEach((line) => {
+          lineclip(line, bbox2, lines);
+        });
+        if (lines.length === 1) {
+          return lineString(lines[0], properties);
+        }
+        return multiLineString(lines, properties);
+      }
+      case "Polygon":
+        return polygon(clipPolygon(coords, bbox2), properties);
+      case "MultiPolygon":
+        return multiPolygon(
+          coords.map((poly) => {
+            return clipPolygon(poly, bbox2);
+          }),
+          properties
+        );
+      default:
+        throw new Error("geometry " + type2 + " not supported");
     }
-    function choose(d3_event, ul, datum2) {
-      if (d3_event)
-        d3_event.preventDefault();
-      select_default2(ul).selectAll("li").classed("active", function(d) {
-        return d === datum2;
-      }).selectAll("input").property("checked", function(d) {
-        return d === datum2;
-      });
-      var extent = geoExtent();
-      var entity;
-      entity = context.graph().hasEntity(datum2.id);
-      if (entity)
-        extent._extend(entity.extent(context.graph()));
-      datum2.action();
-      entity = context.graph().hasEntity(datum2.id);
-      if (entity)
-        extent._extend(entity.extent(context.graph()));
-      zoomToEntity(datum2.id, extent);
+  }
+  function clipPolygon(rings, bbox2) {
+    const outRings = [];
+    for (const ring of rings) {
+      const clipped = polygonclip(ring, bbox2);
+      if (clipped.length > 0) {
+        if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
+          clipped.push(clipped[0]);
+        }
+        if (clipped.length >= 4) {
+          outRings.push(clipped);
+        }
+      }
     }
-    function zoomToEntity(id2, extent) {
-      context.surface().selectAll(".hover").classed("hover", false);
-      var entity = context.graph().hasEntity(id2);
-      if (entity) {
-        if (extent) {
-          context.map().trimmedExtent(extent);
-        } else {
-          context.map().zoomToEase(entity);
+    return outRings;
+  }
+  var turf_bbox_clip_default = bboxClip;
+
+  // node_modules/@turf/meta/dist/esm/index.js
+  function coordEach(geojson, callback, excludeWrapCoord) {
+    if (geojson === null)
+      return;
+    var j2, k2, l2, geometry, stopG, coords, geometryMaybeCollection, wrapShrink = 0, coordIndex = 0, isGeometryCollection, type2 = geojson.type, isFeatureCollection = type2 === "FeatureCollection", isFeature = type2 === "Feature", stop = isFeatureCollection ? geojson.features.length : 1;
+    for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
+      geometryMaybeCollection = isFeatureCollection ? geojson.features[featureIndex].geometry : isFeature ? geojson.geometry : geojson;
+      isGeometryCollection = geometryMaybeCollection ? geometryMaybeCollection.type === "GeometryCollection" : false;
+      stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
+      for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
+        var multiFeatureIndex = 0;
+        var geometryIndex = 0;
+        geometry = isGeometryCollection ? geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
+        if (geometry === null)
+          continue;
+        coords = geometry.coordinates;
+        var geomType = geometry.type;
+        wrapShrink = excludeWrapCoord && (geomType === "Polygon" || geomType === "MultiPolygon") ? 1 : 0;
+        switch (geomType) {
+          case null:
+            break;
+          case "Point":
+            if (callback(
+              coords,
+              coordIndex,
+              featureIndex,
+              multiFeatureIndex,
+              geometryIndex
+            ) === false)
+              return false;
+            coordIndex++;
+            multiFeatureIndex++;
+            break;
+          case "LineString":
+          case "MultiPoint":
+            for (j2 = 0; j2 < coords.length; j2++) {
+              if (callback(
+                coords[j2],
+                coordIndex,
+                featureIndex,
+                multiFeatureIndex,
+                geometryIndex
+              ) === false)
+                return false;
+              coordIndex++;
+              if (geomType === "MultiPoint")
+                multiFeatureIndex++;
+            }
+            if (geomType === "LineString")
+              multiFeatureIndex++;
+            break;
+          case "Polygon":
+          case "MultiLineString":
+            for (j2 = 0; j2 < coords.length; j2++) {
+              for (k2 = 0; k2 < coords[j2].length - wrapShrink; k2++) {
+                if (callback(
+                  coords[j2][k2],
+                  coordIndex,
+                  featureIndex,
+                  multiFeatureIndex,
+                  geometryIndex
+                ) === false)
+                  return false;
+                coordIndex++;
+              }
+              if (geomType === "MultiLineString")
+                multiFeatureIndex++;
+              if (geomType === "Polygon")
+                geometryIndex++;
+            }
+            if (geomType === "Polygon")
+              multiFeatureIndex++;
+            break;
+          case "MultiPolygon":
+            for (j2 = 0; j2 < coords.length; j2++) {
+              geometryIndex = 0;
+              for (k2 = 0; k2 < coords[j2].length; k2++) {
+                for (l2 = 0; l2 < coords[j2][k2].length - wrapShrink; l2++) {
+                  if (callback(
+                    coords[j2][k2][l2],
+                    coordIndex,
+                    featureIndex,
+                    multiFeatureIndex,
+                    geometryIndex
+                  ) === false)
+                    return false;
+                  coordIndex++;
+                }
+                geometryIndex++;
+              }
+              multiFeatureIndex++;
+            }
+            break;
+          case "GeometryCollection":
+            for (j2 = 0; j2 < geometry.geometries.length; j2++)
+              if (coordEach(geometry.geometries[j2], callback, excludeWrapCoord) === false)
+                return false;
+            break;
+          default:
+            throw new Error("Unknown Geometry Type");
         }
-        context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
       }
     }
-    conflicts.conflictList = function(_) {
-      if (!arguments.length)
-        return _conflictList;
-      _conflictList = _;
-      return conflicts;
-    };
-    conflicts.origChanges = function(_) {
-      if (!arguments.length)
-        return _origChanges;
-      _origChanges = _;
-      return conflicts;
-    };
-    conflicts.shownEntityIds = function() {
-      if (_conflictList && typeof _shownConflictIndex === "number") {
-        return [_conflictList[_shownConflictIndex].id];
+  }
+
+  // node_modules/@turf/bbox/dist/esm/index.js
+  function bbox(geojson, options2 = {}) {
+    if (geojson.bbox != null && true !== options2.recompute) {
+      return geojson.bbox;
+    }
+    const result = [Infinity, Infinity, -Infinity, -Infinity];
+    coordEach(geojson, (coord2) => {
+      if (result[0] > coord2[0]) {
+        result[0] = coord2[0];
       }
-      return [];
-    };
-    return utilRebind(conflicts, dispatch10, "on");
+      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;
   }
+  var turf_bbox_default = bbox;
 
-  // modules/ui/entity_editor.js
-  var import_fast_deep_equal10 = __toESM(require_fast_deep_equal());
+  // modules/renderer/background.js
+  var import_which_polygon3 = __toESM(require_which_polygon());
 
-  // modules/ui/sections/entity_issues.js
-  function uiSectionEntityIssues(context) {
-    var preference = corePreferences("entity-issues.reference.expanded");
-    var _expanded = preference === null ? true : preference === "true";
-    var _entityIDs = [];
-    var _issues = [];
-    var _activeIssueID;
-    var section = uiSection("entity-issues", context).shouldDisplay(function() {
-      return _issues.length > 0;
-    }).label(function() {
-      return _t.append("inspector.title_count", { title: _t("issues.list_title"), count: _issues.length });
-    }).disclosureContent(renderDisclosureContent);
-    context.validator().on("validated.entity_issues", function() {
-      reloadIssues();
-      section.reRender();
-    }).on("focusedIssue.entity_issues", function(issue) {
-      makeActiveIssue(issue.id);
-    });
-    function reloadIssues() {
-      _issues = context.validator().getSharedEntityIssues(_entityIDs, { includeDisabledRules: true });
+  // modules/renderer/tile_layer.js
+  function rendererTileLayer(context) {
+    var transformProp = utilPrefixCSSProperty("Transform");
+    var tiler8 = utilTiler();
+    var _tileSize = 256;
+    var _projection;
+    var _cache5 = {};
+    var _tileOrigin;
+    var _zoom;
+    var _source;
+    function tileSizeAtZoom(d2, z2) {
+      var EPSILON = 2e-3;
+      return _tileSize * Math.pow(2, z2 - d2[2]) / _tileSize + EPSILON;
     }
-    function makeActiveIssue(issueID) {
-      _activeIssueID = issueID;
-      section.selection().selectAll(".issue-container").classed("active", function(d) {
-        return d.id === _activeIssueID;
-      });
+    function atZoom(t2, distance) {
+      var power = Math.pow(2, distance);
+      return [
+        Math.floor(t2[0] * power),
+        Math.floor(t2[1] * power),
+        t2[2] + distance
+      ];
     }
-    function renderDisclosureContent(selection2) {
-      selection2.classed("grouped-items-area", true);
-      _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
-      var containers = selection2.selectAll(".issue-container").data(_issues, function(d) {
-        return d.key;
-      });
-      containers.exit().remove();
-      var containersEnter = containers.enter().append("div").attr("class", "issue-container");
-      var itemsEnter = containersEnter.append("div").attr("class", function(d) {
-        return "issue severity-" + d.severity;
-      }).on("mouseover.highlight", function(d3_event, d) {
-        var ids = d.entityIds.filter(function(e) {
-          return _entityIDs.indexOf(e) === -1;
-        });
-        utilHighlightEntities(ids, true, context);
-      }).on("mouseout.highlight", function(d3_event, d) {
-        var ids = d.entityIds.filter(function(e) {
-          return _entityIDs.indexOf(e) === -1;
-        });
-        utilHighlightEntities(ids, false, context);
-      });
-      var labelsEnter = itemsEnter.append("div").attr("class", "issue-label");
-      var textEnter = labelsEnter.append("button").attr("class", "issue-text").on("click", function(d3_event, d) {
-        makeActiveIssue(d.id);
-        var extent = d.extent(context.graph());
-        if (extent) {
-          var setZoom = Math.max(context.map().zoom(), 19);
-          context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
-        }
-      });
-      textEnter.each(function(d) {
-        var iconName = "#iD-icon-" + (d.severity === "warning" ? "alert" : "error");
-        select_default2(this).call(svgIcon(iconName, "issue-icon"));
-      });
-      textEnter.append("span").attr("class", "issue-message");
-      var infoButton = labelsEnter.append("button").attr("class", "issue-info-button").attr("title", _t("icons.information")).call(svgIcon("#iD-icon-inspect"));
-      infoButton.on("click", function(d3_event) {
-        d3_event.stopPropagation();
-        d3_event.preventDefault();
-        this.blur();
-        var container = select_default2(this.parentNode.parentNode.parentNode);
-        var info = container.selectAll(".issue-info");
-        var isExpanded = info.classed("expanded");
-        _expanded = !isExpanded;
-        corePreferences("entity-issues.reference.expanded", _expanded);
-        if (isExpanded) {
-          info.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
-            info.classed("expanded", false);
-          });
-        } else {
-          info.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1").on("end", function() {
-            info.style("max-height", null);
-          });
-        }
-      });
-      itemsEnter.append("ul").attr("class", "issue-fix-list");
-      containersEnter.append("div").attr("class", "issue-info" + (_expanded ? " expanded" : "")).style("max-height", _expanded ? null : "0").style("opacity", _expanded ? "1" : "0").each(function(d) {
-        if (typeof d.reference === "function") {
-          select_default2(this).call(d.reference);
-        } else {
-          select_default2(this).call(_t.append("inspector.no_documentation_key"));
-        }
-      });
-      containers = containers.merge(containersEnter).classed("active", function(d) {
-        return d.id === _activeIssueID;
-      });
-      containers.selectAll(".issue-message").text("").each(function(d) {
-        return d.message(context)(select_default2(this));
-      });
-      var fixLists = containers.selectAll(".issue-fix-list");
-      var fixes = fixLists.selectAll(".issue-fix-item").data(function(d) {
-        return d.fixes ? d.fixes(context) : [];
-      }, function(fix) {
-        return fix.id;
-      });
-      fixes.exit().remove();
-      var fixesEnter = fixes.enter().append("li").attr("class", "issue-fix-item");
-      var buttons = fixesEnter.append("button").on("click", function(d3_event, d) {
-        if (select_default2(this).attr("disabled") || !d.onClick)
-          return;
-        if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1e3)
-          return;
-        d.issue.dateLastRanFix = new Date();
-        utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
-        new Promise(function(resolve, reject) {
-          d.onClick(context, resolve, reject);
-          if (d.onClick.length <= 1) {
-            resolve();
-          }
-        }).then(function() {
-          context.validator().validate();
-        });
-      }).on("mouseover.highlight", function(d3_event, d) {
-        utilHighlightEntities(d.entityIds, true, context);
-      }).on("mouseout.highlight", function(d3_event, d) {
-        utilHighlightEntities(d.entityIds, false, context);
-      });
-      buttons.each(function(d) {
-        var iconName = d.icon || "iD-icon-wrench";
-        if (iconName.startsWith("maki")) {
-          iconName += "-15";
-        }
-        select_default2(this).call(svgIcon("#" + iconName, "fix-icon"));
-      });
-      buttons.append("span").attr("class", "fix-message").each(function(d) {
-        return d.title(select_default2(this));
-      });
-      fixesEnter.merge(fixes).selectAll("button").classed("actionable", function(d) {
-        return d.onClick;
-      }).attr("disabled", function(d) {
-        return d.onClick ? null : "true";
-      }).attr("title", function(d) {
-        if (d.disabledReason) {
-          return d.disabledReason;
+    function lookUp(d2) {
+      for (var up = -1; up > -d2[2]; up--) {
+        var tile = atZoom(d2, up);
+        if (_cache5[_source.url(tile)] !== false) {
+          return tile;
         }
-        return null;
-      });
-    }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
-        _entityIDs = val;
-        _activeIssueID = null;
-        reloadIssues();
       }
-      return section;
-    };
-    return section;
-  }
-
-  // modules/ui/preset_icon.js
-  function uiPresetIcon() {
-    let _preset;
-    let _geometry;
-    function presetIcon(selection2) {
-      selection2.each(render);
     }
-    function getIcon(p, geom) {
-      if (p.isFallback && p.isFallback())
-        return geom === "vertex" ? "" : "iD-icon-" + p.id;
-      if (p.icon)
-        return p.icon;
-      if (geom === "line")
-        return "iD-other-line";
-      if (geom === "vertex")
-        return "temaki-vertex";
-      return "maki-marker-stroked";
+    function uniqueBy(a2, n3) {
+      var o2 = [];
+      var seen = {};
+      for (var i3 = 0; i3 < a2.length; i3++) {
+        if (seen[a2[i3][n3]] === void 0) {
+          o2.push(a2[i3]);
+          seen[a2[i3][n3]] = true;
+        }
+      }
+      return o2;
     }
-    function renderPointBorder(container, drawPoint) {
-      let pointBorder = container.selectAll(".preset-icon-point-border").data(drawPoint ? [0] : []);
-      pointBorder.exit().remove();
-      let pointBorderEnter = pointBorder.enter();
-      const w = 40;
-      const h = 40;
-      pointBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-point-border").attr("width", w).attr("height", h).attr("viewBox", `0 0 ${w} ${h}`).append("path").attr("transform", "translate(11.5, 8)").attr("d", "M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z");
-      pointBorder = pointBorderEnter.merge(pointBorder);
+    function addSource(d2) {
+      d2.push(_source.url(d2));
+      return d2;
     }
-    function renderCategoryBorder(container, category) {
-      let categoryBorder = container.selectAll(".preset-icon-category-border").data(category ? [0] : []);
-      categoryBorder.exit().remove();
-      let categoryBorderEnter = categoryBorder.enter();
-      const d = 60;
-      let svgEnter = categoryBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-category-border").attr("width", d).attr("height", d).attr("viewBox", `0 0 ${d} ${d}`);
-      svgEnter.append("path").attr("class", "area").attr("d", "M9.5,7.5 L25.5,7.5 L28.5,12.5 L49.5,12.5 C51.709139,12.5 53.5,14.290861 53.5,16.5 L53.5,43.5 C53.5,45.709139 51.709139,47.5 49.5,47.5 L10.5,47.5 C8.290861,47.5 6.5,45.709139 6.5,43.5 L6.5,12.5 L9.5,7.5 Z");
-      categoryBorder = categoryBorderEnter.merge(categoryBorder);
-      if (category) {
-        categoryBorder.selectAll("path").attr("class", `area ${category.id}`);
+    function background(selection2) {
+      _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
+      var pixelOffset;
+      if (_source) {
+        pixelOffset = [
+          _source.offset()[0] * Math.pow(2, _zoom),
+          _source.offset()[1] * Math.pow(2, _zoom)
+        ];
+      } else {
+        pixelOffset = [0, 0];
       }
+      var translate = [
+        _projection.translate()[0] + pixelOffset[0],
+        _projection.translate()[1] + pixelOffset[1]
+      ];
+      tiler8.scale(_projection.scale() * 2 * Math.PI).translate(translate);
+      _tileOrigin = [
+        _projection.scale() * Math.PI - translate[0],
+        _projection.scale() * Math.PI - translate[1]
+      ];
+      render(selection2);
     }
-    function renderCircleFill(container, drawVertex) {
-      let vertexFill = container.selectAll(".preset-icon-fill-vertex").data(drawVertex ? [0] : []);
-      vertexFill.exit().remove();
-      let vertexFillEnter = vertexFill.enter();
-      const w = 60;
-      const h = 60;
-      const d = 40;
-      vertexFillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-vertex").attr("width", w).attr("height", h).attr("viewBox", `0 0 ${w} ${h}`).append("circle").attr("cx", w / 2).attr("cy", h / 2).attr("r", d / 2);
-      vertexFill = vertexFillEnter.merge(vertexFill);
-    }
-    function renderSquareFill(container, drawArea, tagClasses) {
-      let fill = container.selectAll(".preset-icon-fill-area").data(drawArea ? [0] : []);
-      fill.exit().remove();
-      let fillEnter = fill.enter();
-      const d = 60;
-      const w = d;
-      const h = d;
-      const l = d * 2 / 3;
-      const c1 = (w - l) / 2;
-      const c2 = c1 + l;
-      fillEnter = fillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-area").attr("width", w).attr("height", h).attr("viewBox", `0 0 ${w} ${h}`);
-      ["fill", "stroke"].forEach((klass) => {
-        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);
-      });
-      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);
+    function render(selection2) {
+      if (!_source) return;
+      var requests = [];
+      var showDebug = context.getDebug("tile") && !_source.overlay;
+      if (_source.validZoom(_zoom)) {
+        tiler8.skipNullIsland(!!_source.overlay);
+        tiler8().forEach(function(d2) {
+          addSource(d2);
+          if (d2[3] === "") return;
+          if (typeof d2[3] !== "string") return;
+          requests.push(d2);
+          if (_cache5[d2[3]] === false && lookUp(d2)) {
+            requests.push(addSource(lookUp(d2)));
+          }
+        });
+        requests = uniqueBy(requests, 3).filter(function(r2) {
+          return _cache5[r2[3]] !== false;
+        });
+      }
+      function load(d3_event, d2) {
+        _cache5[d2[3]] = true;
+        select_default2(this).on("error", null).on("load", null).classed("tile-loaded", true);
+        render(selection2);
+      }
+      function error(d3_event, d2) {
+        _cache5[d2[3]] = false;
+        select_default2(this).on("error", null).on("load", null).remove();
+        render(selection2);
+      }
+      function imageTransform(d2) {
+        var ts = _tileSize * Math.pow(2, _zoom - d2[2]);
+        var scale = tileSizeAtZoom(d2, _zoom);
+        return "translate(" + (d2[0] * ts - _tileOrigin[0]) + "px," + (d2[1] * ts - _tileOrigin[1]) + "px) scale(" + scale + "," + scale + ")";
+      }
+      function tileCenter(d2) {
+        var ts = _tileSize * Math.pow(2, _zoom - d2[2]);
+        return [
+          d2[0] * ts - _tileOrigin[0] + ts / 2,
+          d2[1] * ts - _tileOrigin[1] + ts / 2
+        ];
+      }
+      function debugTransform(d2) {
+        var coord2 = tileCenter(d2);
+        return "translate(" + coord2[0] + "px," + coord2[1] + "px)";
+      }
+      var dims = tiler8.size();
+      var mapCenter = [dims[0] / 2, dims[1] / 2];
+      var minDist = Math.max(dims[0], dims[1]);
+      var nearCenter;
+      requests.forEach(function(d2) {
+        var c2 = tileCenter(d2);
+        var dist = geoVecLength(c2, mapCenter);
+        if (dist < minDist) {
+          minDist = dist;
+          nearCenter = d2;
+        }
       });
-      fill = fillEnter.merge(fill);
-      fill.selectAll("path.stroke").attr("class", `area stroke ${tagClasses}`);
-      fill.selectAll("path.fill").attr("class", `area fill ${tagClasses}`);
-    }
-    function renderLine(container, drawLine, tagClasses) {
-      let line = container.selectAll(".preset-icon-line").data(drawLine ? [0] : []);
-      line.exit().remove();
-      let lineEnter = line.enter();
-      const d = 60;
-      const w = d;
-      const h = d;
-      const y = Math.round(d * 0.72);
-      const l = Math.round(d * 0.6);
-      const r = 2.5;
-      const x12 = (w - l) / 2;
-      const x2 = x12 + l;
-      lineEnter = lineEnter.append("svg").attr("class", "preset-icon-line").attr("width", w).attr("height", h).attr("viewBox", `0 0 ${w} ${h}`);
-      ["casing", "stroke"].forEach((klass) => {
-        lineEnter.append("path").attr("d", `M${x12} ${y} L${x2} ${y}`).attr("class", `line ${klass}`);
+      var image = selection2.selectAll("img").data(requests, function(d2) {
+        return d2[3];
       });
-      [[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);
+      image.exit().style(transformProp, imageTransform).classed("tile-removing", true).classed("tile-center", false).each(function() {
+        var tile = select_default2(this);
+        window.setTimeout(function() {
+          if (tile.classed("tile-removing")) {
+            tile.remove();
+          }
+        }, 300);
       });
-      line = lineEnter.merge(line);
-      line.selectAll("path.stroke").attr("class", `line stroke ${tagClasses}`);
-      line.selectAll("path.casing").attr("class", `line casing ${tagClasses}`);
-    }
-    function renderRoute(container, drawRoute, p) {
-      let route = container.selectAll(".preset-icon-route").data(drawRoute ? [0] : []);
-      route.exit().remove();
-      let routeEnter = route.enter();
-      const d = 60;
-      const w = d;
-      const h = d;
-      const y12 = Math.round(d * 0.8);
-      const y2 = Math.round(d * 0.68);
-      const l = Math.round(d * 0.6);
-      const r = 2;
-      const x12 = (w - l) / 2;
-      const x2 = x12 + l / 3;
-      const x3 = x2 + l / 3;
-      const x4 = x3 + l / 3;
-      routeEnter = routeEnter.append("svg").attr("class", "preset-icon-route").attr("width", w).attr("height", h).attr("viewBox", `0 0 ${w} ${h}`);
-      ["casing", "stroke"].forEach((klass) => {
-        routeEnter.append("path").attr("d", `M${x12} ${y12} L${x2} ${y2}`).attr("class", `segment0 line ${klass}`);
-        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}`);
+      image.enter().append("img").attr("class", "tile").attr("alt", "").attr("draggable", "false").style("width", _tileSize + "px").style("height", _tileSize + "px").attr("src", function(d2) {
+        return d2[3];
+      }).on("error", error).on("load", load).merge(image).style(transformProp, imageTransform).classed("tile-debug", showDebug).classed("tile-removing", false).classed("tile-center", function(d2) {
+        return d2 === nearCenter;
       });
-      [[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);
+      var debug2 = selection2.selectAll(".tile-label-debug").data(showDebug ? requests : [], function(d2) {
+        return d2[3];
       });
-      route = routeEnter.merge(route);
-      if (drawRoute) {
-        let routeType = p.tags.type === "waterway" ? "waterway" : p.tags.route;
-        const segmentPresetIDs = routeSegments[routeType];
-        for (let i2 in segmentPresetIDs) {
-          const segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i2]);
-          const segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, "");
-          route.selectAll(`path.stroke.segment${i2}`).attr("class", `segment${i2} line stroke ${segmentTagClasses}`);
-          route.selectAll(`path.casing.segment${i2}`).attr("class", `segment${i2} line casing ${segmentTagClasses}`);
-        }
+      debug2.exit().remove();
+      if (showDebug) {
+        var debugEnter = debug2.enter().append("div").attr("class", "tile-label-debug");
+        debugEnter.append("div").attr("class", "tile-label-debug-coord");
+        debugEnter.append("div").attr("class", "tile-label-debug-vintage");
+        debug2 = debug2.merge(debugEnter);
+        debug2.style(transformProp, debugTransform);
+        debug2.selectAll(".tile-label-debug-coord").text(function(d2) {
+          return d2[2] + " / " + d2[0] + " / " + d2[1];
+        });
+        debug2.selectAll(".tile-label-debug-vintage").each(function(d2) {
+          var span = select_default2(this);
+          var center = context.projection.invert(tileCenter(d2));
+          _source.getMetadata(center, d2, function(err, result) {
+            if (result && result.vintage && result.vintage.range) {
+              span.text(result.vintage.range);
+            } else {
+              span.text("");
+              span.call(_t.append("info_panels.background.vintage"));
+              span.append("span").text(": ");
+              span.call(_t.append("info_panels.background.unknown"));
+            }
+          });
+        });
       }
     }
-    function renderSvgIcon(container, picon, geom, isFramed, category, tagClasses) {
-      const isMaki = picon && /^maki-/.test(picon);
-      const isTemaki = picon && /^temaki-/.test(picon);
-      const isFa = picon && /^fa[srb]-/.test(picon);
-      const isiDIcon = picon && !(isMaki || isTemaki || isFa);
-      let icon2 = container.selectAll(".preset-icon").data(picon ? [0] : []);
-      icon2.exit().remove();
-      icon2 = icon2.enter().append("div").attr("class", "preset-icon").call(svgIcon("")).merge(icon2);
-      icon2.attr("class", "preset-icon " + (geom ? geom + "-geom" : "")).classed("category", category).classed("framed", isFramed).classed("preset-icon-iD", isiDIcon);
-      icon2.selectAll("svg").attr("class", "icon " + picon + " " + (!isiDIcon && geom !== "line" ? "" : tagClasses));
-      icon2.selectAll("use").attr("href", "#" + picon);
-    }
-    function renderImageIcon(container, imageURL) {
-      let imageIcon = container.selectAll("img.image-icon").data(imageURL ? [0] : []);
-      imageIcon.exit().remove();
-      imageIcon = imageIcon.enter().append("img").attr("class", "image-icon").on("load", () => container.classed("showing-img", true)).on("error", () => container.classed("showing-img", false)).merge(imageIcon);
-      imageIcon.attr("src", imageURL);
-    }
-    const routeSegments = {
-      bicycle: ["highway/cycleway", "highway/cycleway", "highway/cycleway"],
-      bus: ["highway/unclassified", "highway/secondary", "highway/primary"],
-      trolleybus: ["highway/unclassified", "highway/secondary", "highway/primary"],
-      detour: ["highway/tertiary", "highway/residential", "highway/unclassified"],
-      ferry: ["route/ferry", "route/ferry", "route/ferry"],
-      foot: ["highway/footway", "highway/footway", "highway/footway"],
-      hiking: ["highway/path", "highway/path", "highway/path"],
-      horse: ["highway/bridleway", "highway/bridleway", "highway/bridleway"],
-      light_rail: ["railway/light_rail", "railway/light_rail", "railway/light_rail"],
-      monorail: ["railway/monorail", "railway/monorail", "railway/monorail"],
-      mtb: ["highway/path", "highway/track", "highway/bridleway"],
-      pipeline: ["man_made/pipeline", "man_made/pipeline", "man_made/pipeline"],
-      piste: ["piste/downhill", "piste/hike", "piste/nordic"],
-      power: ["power/line", "power/line", "power/line"],
-      road: ["highway/secondary", "highway/primary", "highway/trunk"],
-      subway: ["railway/subway", "railway/subway", "railway/subway"],
-      train: ["railway/rail", "railway/rail", "railway/rail"],
-      tram: ["railway/tram", "railway/tram", "railway/tram"],
-      waterway: ["waterway/stream", "waterway/stream", "waterway/stream"]
+    background.projection = function(val) {
+      if (!arguments.length) return _projection;
+      _projection = val;
+      return background;
     };
-    function render() {
-      let p = _preset.apply(this, arguments);
-      let geom = _geometry ? _geometry.apply(this, arguments) : null;
-      if (geom === "relation" && p.tags && (p.tags.type === "route" && p.tags.route && routeSegments[p.tags.route] || p.tags.type === "waterway")) {
-        geom = "route";
-      }
-      const showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
-      const isFallback = p.isFallback && p.isFallback();
-      const imageURL = showThirdPartyIcons === "true" && p.imageURL;
-      const picon = getIcon(p, geom);
-      const isCategory = !p.setTags;
-      const drawPoint = false;
-      const drawVertex = picon !== null && geom === "vertex";
-      const drawLine = picon && geom === "line" && !isFallback && !isCategory;
-      const drawArea = picon && geom === "area" && !isFallback && !isCategory;
-      const drawRoute = picon && geom === "route";
-      const isFramed = drawVertex || drawArea || drawLine || drawRoute || isCategory;
-      let tags = !isCategory ? p.setTags({}, geom) : {};
-      for (let k in tags) {
-        if (tags[k] === "*") {
-          tags[k] = "yes";
-        }
-      }
-      let tagClasses = svgTagClasses().getClassesString(tags, "");
-      let selection2 = select_default2(this);
-      let container = selection2.selectAll(".preset-icon-container").data([0]);
-      container = container.enter().append("div").attr("class", "preset-icon-container").merge(container);
-      container.classed("showing-img", !!imageURL).classed("fallback", isFallback);
-      renderCategoryBorder(container, isCategory && p);
-      renderPointBorder(container, drawPoint);
-      renderCircleFill(container, drawVertex);
-      renderSquareFill(container, drawArea, tagClasses);
-      renderLine(container, drawLine, tagClasses);
-      renderRoute(container, drawRoute, p);
-      renderSvgIcon(container, picon, geom, isFramed, isCategory, tagClasses);
-      renderImageIcon(container, imageURL);
-    }
-    presetIcon.preset = function(val) {
-      if (!arguments.length)
-        return _preset;
-      _preset = utilFunctor(val);
-      return presetIcon;
+    background.dimensions = function(val) {
+      if (!arguments.length) return tiler8.size();
+      tiler8.size(val);
+      return background;
     };
-    presetIcon.geometry = function(val) {
-      if (!arguments.length)
-        return _geometry;
-      _geometry = utilFunctor(val);
-      return presetIcon;
+    background.source = function(val) {
+      if (!arguments.length) return _source;
+      _source = val;
+      _tileSize = _source.tileSize;
+      _cache5 = {};
+      tiler8.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
+      return background;
     };
-    return presetIcon;
+    return background;
   }
 
-  // modules/ui/sections/feature_type.js
-  function uiSectionFeatureType(context) {
-    var dispatch10 = dispatch_default("choose");
-    var _entityIDs = [];
-    var _presets = [];
-    var _tagReference;
-    var section = uiSection("feature-type", context).label(() => _t.append("inspector.feature_type")).disclosureContent(renderDisclosureContent);
-    function renderDisclosureContent(selection2) {
-      selection2.classed("preset-list-item", true);
-      selection2.classed("mixed-types", _presets.length > 1);
-      var presetButtonWrap = selection2.selectAll(".preset-list-button-wrap").data([0]).enter().append("div").attr("class", "preset-list-button-wrap");
-      var presetButton = presetButtonWrap.append("button").attr("class", "preset-list-button preset-reset").call(
-        uiTooltip().title(() => _t.append("inspector.back_tooltip")).placement("bottom")
-      );
-      presetButton.append("div").attr("class", "preset-icon-container");
-      presetButton.append("div").attr("class", "label").append("div").attr("class", "label-inner");
-      presetButtonWrap.append("div").attr("class", "accessory-buttons");
-      var tagReferenceBodyWrap = selection2.selectAll(".tag-reference-body-wrap").data([0]);
-      tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append("div").attr("class", "tag-reference-body-wrap").merge(tagReferenceBodyWrap);
-      if (_tagReference) {
-        selection2.selectAll(".preset-list-button-wrap .accessory-buttons").style("display", _presets.length === 1 ? null : "none").call(_tagReference.button);
-        tagReferenceBodyWrap.style("display", _presets.length === 1 ? null : "none").call(_tagReference.body);
-      }
-      selection2.selectAll(".preset-reset").on("click", function() {
-        dispatch10.call("choose", this, _presets);
-      }).on("pointerdown pointerup mousedown mouseup", function(d3_event) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-      });
-      var geometries = entityGeometries();
-      selection2.select(".preset-list-item button").call(
-        uiPresetIcon().geometry(_presets.length === 1 ? geometries.length === 1 && geometries[0] : null).preset(_presets.length === 1 ? _presets[0] : _mainPresetIndex.item("point"))
-      );
-      var names = _presets.length === 1 ? [
-        _presets[0].nameLabel(),
-        _presets[0].subtitleLabel()
-      ].filter(Boolean) : [_t.append("inspector.multiple_types")];
-      var label = selection2.select(".label-inner");
-      var nameparts = label.selectAll(".namepart").data(names, (d) => d.stringId);
-      nameparts.exit().remove();
-      nameparts.enter().append("div").attr("class", "namepart").text("").each(function(d) {
-        d(select_default2(this));
+  // modules/renderer/background.js
+  var _imageryIndex = null;
+  function rendererBackground(context) {
+    const dispatch14 = dispatch_default("change");
+    const baseLayer = rendererTileLayer(context).projection(context.projection);
+    let _checkedBlocklists = [];
+    let _isValid = true;
+    let _overlayLayers = [];
+    let _brightness = 1;
+    let _contrast = 1;
+    let _saturation = 1;
+    let _sharpness = 1;
+    function ensureImageryIndex() {
+      return _mainFileFetcher.get("imagery").then((sources) => {
+        if (_imageryIndex) return _imageryIndex;
+        _imageryIndex = {
+          imagery: sources,
+          features: {}
+        };
+        const features = sources.map((source) => {
+          if (!source.polygon) return null;
+          const rings = source.polygon.map((ring) => [ring]);
+          const feature3 = {
+            type: "Feature",
+            properties: { id: source.id },
+            geometry: { type: "MultiPolygon", coordinates: rings }
+          };
+          _imageryIndex.features[source.id] = feature3;
+          return feature3;
+        }).filter(Boolean);
+        _imageryIndex.query = (0, import_which_polygon3.default)({ type: "FeatureCollection", features });
+        _imageryIndex.backgrounds = sources.map((source) => {
+          if (source.type === "bing") {
+            return rendererBackgroundSource.Bing(source, dispatch14);
+          } else if (/^EsriWorldImagery/.test(source.id)) {
+            return rendererBackgroundSource.Esri(source);
+          } else {
+            return rendererBackgroundSource(source);
+          }
+        });
+        _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None());
+        let template = corePreferences("background-custom-template") || "";
+        const custom = rendererBackgroundSource.Custom(template);
+        _imageryIndex.backgrounds.unshift(custom);
+        return _imageryIndex;
       });
     }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return section;
-    };
-    section.presets = function(val) {
-      if (!arguments.length)
-        return _presets;
-      if (!utilArrayIdentical(val, _presets)) {
-        _presets = val;
-        if (_presets.length === 1) {
-          _tagReference = uiTagReference(_presets[0].reference(), context).showing(false);
+    function background(selection2) {
+      const currSource = baseLayer.source();
+      if (context.map().zoom() > 18) {
+        if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
+          const center = context.map().center();
+          currSource.fetchTilemap(center);
         }
       }
-      return section;
-    };
-    function entityGeometries() {
-      var counts = {};
-      for (var i2 in _entityIDs) {
-        var geometry = context.graph().geometry(_entityIDs[i2]);
-        if (!counts[geometry])
-          counts[geometry] = 0;
-        counts[geometry] += 1;
+      const sources = background.sources(context.map().extent());
+      const wasValid = _isValid;
+      _isValid = !!sources.filter((d2) => d2 === currSource).length;
+      if (wasValid !== _isValid) {
+        background.updateImagery();
       }
-      return Object.keys(counts).sort(function(geom1, geom2) {
-        return counts[geom2] - counts[geom1];
-      });
+      let baseFilter = "";
+      if (_brightness !== 1) {
+        baseFilter += " brightness(".concat(_brightness, ")");
+      }
+      if (_contrast !== 1) {
+        baseFilter += " contrast(".concat(_contrast, ")");
+      }
+      if (_saturation !== 1) {
+        baseFilter += " saturate(".concat(_saturation, ")");
+      }
+      if (_sharpness < 1) {
+        const blur = number_default(0.5, 5)(1 - _sharpness);
+        baseFilter += " blur(".concat(blur, "px)");
+      }
+      let base = selection2.selectAll(".layer-background").data([0]);
+      base = base.enter().insert("div", ".layer-data").attr("class", "layer layer-background").merge(base);
+      base.style("filter", baseFilter || null);
+      let imagery = base.selectAll(".layer-imagery").data([0]);
+      imagery.enter().append("div").attr("class", "layer layer-imagery").merge(imagery).call(baseLayer);
+      let maskFilter = "";
+      let mixBlendMode = "";
+      if (_sharpness > 1) {
+        mixBlendMode = "overlay";
+        maskFilter = "saturate(0) blur(3px) invert(1)";
+        let contrast = _sharpness - 1;
+        maskFilter += " contrast(".concat(contrast, ")");
+        let brightness = number_default(1, 0.85)(_sharpness - 1);
+        maskFilter += " brightness(".concat(brightness, ")");
+      }
+      let mask = base.selectAll(".layer-unsharp-mask").data(_sharpness > 1 ? [0] : []);
+      mask.exit().remove();
+      mask.enter().append("div").attr("class", "layer layer-mask layer-unsharp-mask").merge(mask).call(baseLayer).style("filter", maskFilter || null).style("mix-blend-mode", mixBlendMode || null);
+      let overlays = selection2.selectAll(".layer-overlay").data(_overlayLayers, (d2) => d2.source().name());
+      overlays.exit().remove();
+      overlays.enter().insert("div", ".layer-data").attr("class", "layer layer-overlay").merge(overlays).each((layer, i3, nodes) => select_default2(nodes[i3]).call(layer));
     }
-    return utilRebind(section, dispatch10, "on");
-  }
-
-  // modules/ui/sections/preset_fields.js
-  function uiSectionPresetFields(context) {
-    var section = uiSection("preset-fields", context).label(() => _t.append("inspector.fields")).disclosureContent(renderDisclosureContent);
-    var dispatch10 = dispatch_default("change", "revert");
-    var formFields = uiFormFields(context);
-    var _state;
-    var _fieldsArr;
-    var _presets = [];
-    var _tags;
-    var _entityIDs;
-    function renderDisclosureContent(selection2) {
-      if (!_fieldsArr) {
-        var graph = context.graph();
-        var geometries = Object.keys(_entityIDs.reduce(function(geoms, entityID) {
-          geoms[graph.entity(entityID).geometry(graph)] = true;
-          return geoms;
-        }, {}));
-        var presetsManager = _mainPresetIndex;
-        var allFields = [];
-        var allMoreFields = [];
-        var sharedTotalFields;
-        _presets.forEach(function(preset) {
-          var fields = preset.fields();
-          var moreFields = preset.moreFields();
-          allFields = utilArrayUnion(allFields, fields);
-          allMoreFields = utilArrayUnion(allMoreFields, moreFields);
-          if (!sharedTotalFields) {
-            sharedTotalFields = utilArrayUnion(fields, moreFields);
-          } else {
-            sharedTotalFields = sharedTotalFields.filter(function(field) {
-              return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
-            });
-          }
-        });
-        var sharedFields = allFields.filter(function(field) {
-          return sharedTotalFields.indexOf(field) !== -1;
-        });
-        var sharedMoreFields = allMoreFields.filter(function(field) {
-          return sharedTotalFields.indexOf(field) !== -1;
-        });
-        _fieldsArr = [];
-        sharedFields.forEach(function(field) {
-          if (field.matchAllGeometry(geometries)) {
-            _fieldsArr.push(
-              uiField(context, field, _entityIDs)
-            );
-          }
-        });
-        var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
-        if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field("restrictions")) {
-          _fieldsArr.push(
-            uiField(context, presetsManager.field("restrictions"), _entityIDs)
-          );
+    background.updateImagery = function() {
+      let currSource = baseLayer.source();
+      if (context.inIntro() || !currSource) return;
+      let o2 = _overlayLayers.filter((d2) => !d2.source().isLocatorOverlay() && !d2.source().isHidden()).map((d2) => d2.source().id).join(",");
+      const meters = geoOffsetToMeters(currSource.offset());
+      const EPSILON = 0.01;
+      const x2 = +meters[0].toFixed(2);
+      const y2 = +meters[1].toFixed(2);
+      let hash = utilStringQs(window.location.hash);
+      let id2 = currSource.id;
+      if (id2 === "custom") {
+        id2 = "custom:".concat(currSource.template());
+      }
+      if (id2) {
+        hash.background = id2;
+      } else {
+        delete hash.background;
+      }
+      if (o2) {
+        hash.overlays = o2;
+      } else {
+        delete hash.overlays;
+      }
+      if (Math.abs(x2) > EPSILON || Math.abs(y2) > EPSILON) {
+        hash.offset = "".concat(x2, ",").concat(y2);
+      } else {
+        delete hash.offset;
+      }
+      if (!window.mocha) {
+        window.location.replace("#" + utilQsString(hash, true));
+      }
+      let imageryUsed = [];
+      let photoOverlaysUsed = [];
+      const currUsed = currSource.imageryUsed();
+      if (currUsed && _isValid) {
+        imageryUsed.push(currUsed);
+      }
+      _overlayLayers.filter((d2) => !d2.source().isLocatorOverlay() && !d2.source().isHidden()).forEach((d2) => imageryUsed.push(d2.source().imageryUsed()));
+      const dataLayer = context.layers().layer("data");
+      if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
+        imageryUsed.push(dataLayer.getSrc());
+      }
+      const photoOverlayLayers = {
+        streetside: "Bing Streetside",
+        mapillary: "Mapillary Images",
+        "mapillary-map-features": "Mapillary Map Features",
+        "mapillary-signs": "Mapillary Signs",
+        kartaview: "KartaView Images",
+        vegbilder: "Norwegian Road Administration Images",
+        mapilio: "Mapilio Images",
+        panoramax: "Panoramax Images"
+      };
+      for (let layerID in photoOverlayLayers) {
+        const layer = context.layers().layer(layerID);
+        if (layer && layer.enabled()) {
+          photoOverlaysUsed.push(layerID);
+          imageryUsed.push(photoOverlayLayers[layerID]);
         }
-        var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
-        additionalFields.sort(function(field1, field2) {
-          return field1.title().localeCompare(field2.title(), _mainLocalizer.localeCode());
-        });
-        additionalFields.forEach(function(field) {
-          if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
-            _fieldsArr.push(
-              uiField(context, field, _entityIDs, { show: false })
-            );
-          }
-        });
-        _fieldsArr.forEach(function(field) {
-          field.on("change", function(t, onInput) {
-            dispatch10.call("change", field, _entityIDs, t, onInput);
-          }).on("revert", function(keys) {
-            dispatch10.call("revert", field, keys);
-          });
+      }
+      context.history().imageryUsed(imageryUsed);
+      context.history().photoOverlaysUsed(photoOverlaysUsed);
+    };
+    background.sources = (extent, zoom, includeCurrent) => {
+      if (!_imageryIndex) return [];
+      let visible = {};
+      (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach((d2) => visible[d2.id] = true);
+      const currSource = baseLayer.source();
+      const osm = context.connection();
+      const blocklists = osm && osm.imageryBlocklists() || [];
+      const blocklistChanged = blocklists.length !== _checkedBlocklists.length || blocklists.some((regex, index) => String(regex) !== _checkedBlocklists[index]);
+      if (blocklistChanged) {
+        _imageryIndex.backgrounds.forEach((source) => {
+          source.isBlocked = blocklists.some((regex) => regex.test(source.template()));
         });
+        _checkedBlocklists = blocklists.map((regex) => String(regex));
       }
-      _fieldsArr.forEach(function(field) {
-        field.state(_state).tags(_tags);
-      });
-      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));
-        }
+      return _imageryIndex.backgrounds.filter((source) => {
+        if (includeCurrent && currSource === source) return true;
+        if (source.isBlocked) return false;
+        if (!source.polygon) return true;
+        if (zoom && zoom < 6) return false;
+        return visible[source.id];
       });
-    }
-    section.presets = function(val) {
-      if (!arguments.length)
-        return _presets;
-      if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
-        _presets = val;
-        _fieldsArr = null;
+    };
+    background.dimensions = (val) => {
+      if (!val) return;
+      baseLayer.dimensions(val);
+      _overlayLayers.forEach((layer) => layer.dimensions(val));
+    };
+    background.baseLayerSource = function(d2) {
+      if (!arguments.length) return baseLayer.source();
+      const osm = context.connection();
+      if (!osm) return background;
+      const blocklists = osm.imageryBlocklists();
+      const template = d2.template();
+      let fail = false;
+      let tested = 0;
+      let regex;
+      for (let i3 = 0; i3 < blocklists.length; i3++) {
+        regex = blocklists[i3];
+        fail = regex.test(template);
+        tested++;
+        if (fail) break;
       }
-      return section;
+      if (!tested) {
+        regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
+        fail = regex.test(template);
+      }
+      baseLayer.source(!fail ? d2 : background.findSource("none"));
+      dispatch14.call("change");
+      background.updateImagery();
+      return background;
     };
-    section.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      return section;
+    background.findSource = (id2) => {
+      if (!id2 || !_imageryIndex) return null;
+      return _imageryIndex.backgrounds.find((d2) => d2.id && d2.id === id2);
     };
-    section.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
-      _tags = val;
-      return section;
+    background.bing = () => {
+      background.baseLayerSource(background.findSource("Bing"));
     };
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
-        _entityIDs = val;
-        _fieldsArr = null;
+    background.showsLayer = (d2) => {
+      const currSource = baseLayer.source();
+      if (!d2 || !currSource) return false;
+      return d2.id === currSource.id || _overlayLayers.some((layer) => d2.id === layer.source().id);
+    };
+    background.overlayLayerSources = () => {
+      return _overlayLayers.map((layer) => layer.source());
+    };
+    background.toggleOverlayLayer = (d2) => {
+      let layer;
+      for (let i3 = 0; i3 < _overlayLayers.length; i3++) {
+        layer = _overlayLayers[i3];
+        if (layer.source() === d2) {
+          _overlayLayers.splice(i3, 1);
+          dispatch14.call("change");
+          background.updateImagery();
+          return;
+        }
       }
-      return section;
+      layer = rendererTileLayer(context).source(d2).projection(context.projection).dimensions(
+        baseLayer.dimensions()
+      );
+      _overlayLayers.push(layer);
+      dispatch14.call("change");
+      background.updateImagery();
     };
-    return utilRebind(section, dispatch10, "on");
-  }
-
-  // modules/ui/sections/raw_member_editor.js
-  function uiSectionRawMemberEditor(context) {
-    var section = uiSection("raw-member-editor", context).shouldDisplay(function() {
-      if (!_entityIDs || _entityIDs.length !== 1)
-        return false;
-      var entity = context.hasEntity(_entityIDs[0]);
-      return entity && entity.type === "relation";
-    }).label(function() {
-      var entity = context.hasEntity(_entityIDs[0]);
-      if (!entity)
-        return "";
-      var gt = entity.members.length > _maxMembers ? ">" : "";
-      var count = gt + entity.members.slice(0, _maxMembers).length;
-      return _t.append("inspector.title_count", { title: _t("inspector.members"), count });
-    }).disclosureContent(renderDisclosureContent);
-    var taginfo = services.taginfo;
-    var _entityIDs;
-    var _maxMembers = 1e3;
-    function downloadMember(d3_event, d) {
-      d3_event.preventDefault();
-      select_default2(this.parentNode).classed("tag-reference-loading", true);
-      context.loadEntity(d.id, function() {
-        section.reRender();
-      });
-    }
-    function zoomToMember(d3_event, d) {
-      d3_event.preventDefault();
-      var entity = context.entity(d.id);
-      context.map().zoomToEase(entity);
-      utilHighlightEntities([d.id], true, context);
-    }
-    function selectMember(d3_event, d) {
-      d3_event.preventDefault();
-      utilHighlightEntities([d.id], false, context);
-      var entity = context.entity(d.id);
-      var mapExtent = context.map().extent();
-      if (!entity.intersects(mapExtent, context.graph())) {
-        context.map().zoomToEase(entity);
+    background.nudge = (d2, zoom) => {
+      const currSource = baseLayer.source();
+      if (currSource) {
+        currSource.nudge(d2, zoom);
+        dispatch14.call("change");
+        background.updateImagery();
       }
-      context.enter(modeSelect(context, [d.id]));
-    }
-    function changeRole(d3_event, d) {
-      var oldRole = d.role;
-      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
-      if (oldRole !== newRole) {
-        var member = { id: d.id, type: d.type, role: newRole };
-        context.perform(
-          actionChangeMember(d.relation.id, member, d.index),
-          _t("operations.change_role.annotation", {
-            n: 1
-          })
-        );
-        context.validator().validate();
+      return background;
+    };
+    background.offset = function(d2) {
+      const currSource = baseLayer.source();
+      if (!arguments.length) {
+        return currSource && currSource.offset() || [0, 0];
       }
-    }
-    function deleteMember(d3_event, d) {
-      utilHighlightEntities([d.id], false, context);
-      context.perform(
-        actionDeleteMember(d.relation.id, d.index),
-        _t("operations.delete_member.annotation", {
-          n: 1
-        })
-      );
-      if (!context.hasEntity(d.relation.id)) {
-        context.enter(modeBrowse(context));
-      } else {
-        context.validator().validate();
+      if (currSource) {
+        currSource.offset(d2);
+        dispatch14.call("change");
+        background.updateImagery();
       }
-    }
-    function renderDisclosureContent(selection2) {
-      var entityID = _entityIDs[0];
-      var memberships = [];
-      var entity = context.entity(entityID);
-      entity.members.slice(0, _maxMembers).forEach(function(member, index) {
-        memberships.push({
-          index,
-          id: member.id,
-          type: member.type,
-          role: member.role,
-          relation: entity,
-          member: context.hasEntity(member.id),
-          domId: utilUniqueDomId(entityID + "-member-" + index)
-        });
-      });
-      var list = selection2.selectAll(".member-list").data([0]);
-      list = list.enter().append("ul").attr("class", "member-list").merge(list);
-      var items = list.selectAll("li").data(memberships, function(d) {
-        return osmEntity.key(d.relation) + "," + d.index + "," + (d.member ? osmEntity.key(d.member) : "incomplete");
-      });
-      items.exit().each(unbind).remove();
-      var itemsEnter = items.enter().append("li").attr("class", "member-row form-field").classed("member-incomplete", function(d) {
-        return !d.member;
-      });
-      itemsEnter.each(function(d) {
-        var item = select_default2(this);
-        var label = item.append("label").attr("class", "field-label").attr("for", d.domId);
-        if (d.member) {
-          item.on("mouseover", function() {
-            utilHighlightEntities([d.id], true, context);
-          }).on("mouseout", function() {
-            utilHighlightEntities([d.id], false, context);
-          });
-          var labelLink = label.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectMember);
-          labelLink.append("span").attr("class", "member-entity-type").text(function(d2) {
-            var matched = _mainPresetIndex.match(d2.member, context.graph());
-            return matched && matched.name() || utilDisplayType(d2.member.id);
-          });
-          labelLink.append("span").attr("class", "member-entity-name").text(function(d2) {
-            return utilDisplayName(d2.member);
+      return background;
+    };
+    background.brightness = function(d2) {
+      if (!arguments.length) return _brightness;
+      _brightness = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
+    };
+    background.contrast = function(d2) {
+      if (!arguments.length) return _contrast;
+      _contrast = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
+    };
+    background.saturation = function(d2) {
+      if (!arguments.length) return _saturation;
+      _saturation = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
+    };
+    background.sharpness = function(d2) {
+      if (!arguments.length) return _sharpness;
+      _sharpness = d2;
+      if (context.mode()) dispatch14.call("change");
+      return background;
+    };
+    let _loadPromise;
+    background.ensureLoaded = () => {
+      if (_loadPromise) return _loadPromise;
+      return _loadPromise = ensureImageryIndex();
+    };
+    background.init = () => {
+      const loadPromise = background.ensureLoaded();
+      const hash = utilStringQs(window.location.hash);
+      const requestedBackground = hash.background || hash.layer;
+      const lastUsedBackground = corePreferences("background-last-used");
+      return loadPromise.then((imageryIndex) => {
+        const extent = context.map().extent();
+        const validBackgrounds = background.sources(extent).filter((d2) => d2.id !== "none" && d2.id !== "custom");
+        const first = validBackgrounds.length && validBackgrounds[0];
+        const isLastUsedValid = !!validBackgrounds.find((d2) => d2.id && d2.id === lastUsedBackground);
+        let best;
+        if (!requestedBackground && extent) {
+          const viewArea = extent.area();
+          best = validBackgrounds.find((s2) => {
+            if (!s2.best() || s2.overlay) return false;
+            let bbox2 = turf_bbox_default(turf_bbox_clip_default(
+              { type: "MultiPolygon", coordinates: [s2.polygon || [extent.polygon()]] },
+              extent.rectangle()
+            ));
+            let area = geoExtent(bbox2.slice(0, 2), bbox2.slice(2, 4)).area();
+            return area / viewArea > 0.5;
           });
-          label.append("button").attr("title", _t("icons.remove")).attr("class", "remove member-delete").call(svgIcon("#iD-operation-delete"));
-          label.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToMember);
+        }
+        if (requestedBackground && requestedBackground.indexOf("custom:") === 0) {
+          const template = requestedBackground.replace(/^custom:/, "");
+          const custom = background.findSource("custom");
+          background.baseLayerSource(custom.template(template));
+          corePreferences("background-custom-template", template);
         } else {
-          var labelText = label.append("span").attr("class", "label-text");
-          labelText.append("span").attr("class", "member-entity-type").call(_t.append("inspector." + d.type, { id: d.id }));
-          labelText.append("span").attr("class", "member-entity-name").call(_t.append("inspector.incomplete", { id: d.id }));
-          label.append("button").attr("class", "member-download").attr("title", _t("icons.download")).call(svgIcon("#iD-icon-load")).on("click", downloadMember);
+          background.baseLayerSource(
+            background.findSource(requestedBackground) || best || isLastUsedValid && background.findSource(lastUsedBackground) || background.findSource("Bing") || first || background.findSource("none")
+          );
         }
-      });
-      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
-      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d) {
-        return d.domId;
-      }).property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
-      if (taginfo) {
-        wrapEnter.each(bindTypeahead);
-      }
-      items = items.merge(itemsEnter).order();
-      items.select("input.member-role").property("value", function(d) {
-        return d.role;
-      }).on("blur", changeRole).on("change", changeRole);
-      items.select("button.member-delete").on("click", deleteMember);
-      var dragOrigin, targetIndex;
-      items.call(
-        drag_default().on("start", function(d3_event) {
-          dragOrigin = {
-            x: d3_event.x,
-            y: d3_event.y
-          };
-          targetIndex = null;
-        }).on("drag", function(d3_event) {
-          var 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)
-            return;
-          var index = items.nodes().indexOf(this);
-          select_default2(this).classed("dragging", true);
-          targetIndex = null;
-          selection2.selectAll("li.member-row").style("transform", function(d2, index2) {
-            var node = select_default2(this).node();
-            if (index === index2) {
-              return "translate(" + x + "px, " + y + "px)";
-            } else if (index2 > index && d3_event.y > node.offsetTop) {
-              if (targetIndex === null || index2 > targetIndex) {
-                targetIndex = index2;
-              }
-              return "translateY(-100%)";
-            } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
-              if (targetIndex === null || index2 < targetIndex) {
-                targetIndex = index2;
-              }
-              return "translateY(100%)";
-            }
-            return null;
-          });
-        }).on("end", function(d3_event, d) {
-          if (!select_default2(this).classed("dragging"))
-            return;
-          var index = items.nodes().indexOf(this);
-          select_default2(this).classed("dragging", false);
-          selection2.selectAll("li.member-row").style("transform", null);
-          if (targetIndex !== null) {
-            context.perform(
-              actionMoveMember(d.relation.id, index, targetIndex),
-              _t("operations.reorder_members.annotation")
-            );
-            context.validator().validate();
+        const locator = imageryIndex.backgrounds.find((d2) => d2.overlay && d2.default);
+        if (locator) {
+          background.toggleOverlayLayer(locator);
+        }
+        const overlays = (hash.overlays || "").split(",");
+        overlays.forEach((overlay) => {
+          overlay = background.findSource(overlay);
+          if (overlay) {
+            background.toggleOverlayLayer(overlay);
           }
-        })
-      );
-      function bindTypeahead(d) {
-        var row = select_default2(this);
-        var role = row.selectAll("input.member-role");
-        var origValue = role.property("value");
-        function sort(value, data) {
-          var sameletter = [];
-          var other = [];
-          for (var i2 = 0; i2 < data.length; i2++) {
-            if (data[i2].value.substring(0, value.length) === value) {
-              sameletter.push(data[i2]);
-            } else {
-              other.push(data[i2]);
-            }
+        });
+        if (hash.gpx) {
+          const gpx2 = context.layers().layer("data");
+          if (gpx2) {
+            gpx2.url(hash.gpx, ".gpx");
           }
-          return sameletter.concat(other);
         }
-        role.call(
-          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
-            var geometry;
-            if (d.member) {
-              geometry = context.graph().geometry(d.member.id);
-            } else if (d.type === "relation") {
-              geometry = "relation";
-            } else if (d.type === "way") {
-              geometry = "line";
-            } else {
-              geometry = "point";
-            }
-            var rtype = entity.tags.type;
-            taginfo.roles({
-              debounce: true,
-              rtype: rtype || "",
-              geometry,
-              query: role2
-            }, function(err, data) {
-              if (!err)
-                callback(sort(role2, data));
-            });
-          }).on("cancel", function() {
-            role.property("value", origValue);
-          })
-        );
-      }
-      function unbind() {
-        var row = select_default2(this);
-        row.selectAll("input.member-role").call(uiCombobox.off, context);
-      }
-    }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return section;
+        if (hash.offset) {
+          const offset = hash.offset.replace(/;/g, ",").split(",").map((n3) => !isNaN(n3) && n3);
+          if (offset.length === 2) {
+            background.offset(geoMetersToOffset(offset));
+          }
+        }
+      }).catch((err) => {
+        console.error(err);
+      });
     };
-    return section;
+    return utilRebind(background, dispatch14, "on");
   }
 
-  // modules/actions/delete_members.js
-  function actionDeleteMembers(relationId, memberIndexes) {
-    return function(graph) {
-      memberIndexes.sort((a, b) => b - a);
-      for (var i2 in memberIndexes) {
-        graph = actionDeleteMember(relationId, memberIndexes[i2])(graph);
-      }
-      return graph;
+  // modules/renderer/features.js
+  function rendererFeatures(context) {
+    var dispatch14 = dispatch_default("change", "redraw");
+    var features = utilRebind({}, dispatch14, "on");
+    var _deferred2 = /* @__PURE__ */ new Set();
+    var traffic_roads = {
+      "motorway": true,
+      "motorway_link": true,
+      "trunk": true,
+      "trunk_link": true,
+      "primary": true,
+      "primary_link": true,
+      "secondary": true,
+      "secondary_link": true,
+      "tertiary": true,
+      "tertiary_link": true,
+      "residential": true,
+      "unclassified": true,
+      "living_street": true,
+      "busway": true
     };
-  }
-
-  // modules/ui/sections/raw_membership_editor.js
-  function uiSectionRawMembershipEditor(context) {
-    var section = uiSection("raw-membership-editor", context).shouldDisplay(function() {
-      return _entityIDs && _entityIDs.length;
-    }).label(function() {
-      var parents = getSharedParentRelations();
-      var gt = parents.length > _maxMemberships ? ">" : "";
-      var count = gt + parents.slice(0, _maxMemberships).length;
-      return _t.append("inspector.title_count", { title: _t("inspector.relations"), count });
-    }).disclosureContent(renderDisclosureContent);
-    var taginfo = services.taginfo;
-    var nearbyCombo = uiCombobox(context, "parent-relation").minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function(d3_event, d) {
-      if (d.relation)
-        utilHighlightEntities([d.relation.id], true, context);
-    }).itemsMouseLeave(function(d3_event, d) {
-      if (d.relation)
-        utilHighlightEntities([d.relation.id], false, context);
-    });
-    var _inChange = false;
-    var _entityIDs = [];
-    var _showBlank;
-    var _maxMemberships = 1e3;
-    function getSharedParentRelations() {
-      var parents = [];
-      for (var i2 = 0; i2 < _entityIDs.length; i2++) {
-        var entity = context.graph().hasEntity(_entityIDs[i2]);
-        if (!entity)
-          continue;
-        if (i2 === 0) {
-          parents = context.graph().parentRelations(entity);
+    var service_roads = {
+      "service": true,
+      "road": true,
+      "track": true
+    };
+    var paths = {
+      "path": true,
+      "footway": true,
+      "cycleway": true,
+      "bridleway": true,
+      "steps": true,
+      "ladder": true,
+      "pedestrian": true
+    };
+    var _cullFactor = 1;
+    var _cache5 = {};
+    var _rules = {};
+    var _stats = {};
+    var _keys = [];
+    var _hidden = [];
+    var _forceVisible = {};
+    function update() {
+      if (!window.mocha) {
+        var hash = utilStringQs(window.location.hash);
+        var disabled = features.disabled();
+        if (disabled.length) {
+          hash.disable_features = disabled.join(",");
         } else {
-          parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
+          delete hash.disable_features;
         }
-        if (!parents.length)
-          break;
+        window.location.replace("#" + utilQsString(hash, true));
+        corePreferences("disabled-features", disabled.join(","));
       }
-      return parents;
+      _hidden = features.hidden();
+      dispatch14.call("change");
+      dispatch14.call("redraw");
     }
-    function getMemberships() {
-      var memberships = [];
-      var relations = getSharedParentRelations().slice(0, _maxMemberships);
-      var isMultiselect = _entityIDs.length > 1;
-      var i2, relation, membership, index, member, indexedMember;
-      for (i2 = 0; i2 < relations.length; i2++) {
-        relation = relations[i2];
-        membership = {
-          relation,
-          members: [],
-          hash: osmEntity.key(relation)
-        };
-        for (index = 0; index < relation.members.length; index++) {
-          member = relation.members[index];
-          if (_entityIDs.indexOf(member.id) !== -1) {
-            indexedMember = Object.assign({}, member, { index });
-            membership.members.push(indexedMember);
-            membership.hash += "," + index.toString();
-            if (!isMultiselect) {
-              memberships.push(membership);
-              membership = {
-                relation,
-                members: [],
-                hash: osmEntity.key(relation)
-              };
-            }
-          }
+    function defineRule(k2, filter2, max3) {
+      var isEnabled = true;
+      _keys.push(k2);
+      _rules[k2] = {
+        filter: filter2,
+        enabled: isEnabled,
+        // whether the user wants it enabled..
+        count: 0,
+        currentMax: max3 || Infinity,
+        defaultMax: max3 || Infinity,
+        enable: function() {
+          this.enabled = true;
+          this.currentMax = this.defaultMax;
+        },
+        disable: function() {
+          this.enabled = false;
+          this.currentMax = 0;
+        },
+        hidden: function() {
+          return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
+        },
+        autoHidden: function() {
+          return this.hidden() && this.currentMax > 0;
         }
-        if (membership.members.length)
-          memberships.push(membership);
-      }
-      memberships.forEach(function(membership2) {
-        membership2.domId = utilUniqueDomId("membership-" + membership2.relation.id);
-        var roles = [];
-        membership2.members.forEach(function(member2) {
-          if (roles.indexOf(member2.role) === -1)
-            roles.push(member2.role);
-        });
-        membership2.role = roles.length === 1 ? roles[0] : roles;
-      });
-      return memberships;
-    }
-    function selectRelation(d3_event, d) {
-      d3_event.preventDefault();
-      utilHighlightEntities([d.relation.id], false, context);
-      context.enter(modeSelect(context, [d.relation.id]));
-    }
-    function zoomToRelation(d3_event, d) {
-      d3_event.preventDefault();
-      var entity = context.entity(d.relation.id);
-      context.map().zoomToEase(entity);
-      utilHighlightEntities([d.relation.id], true, context);
-    }
-    function changeRole(d3_event, d) {
-      if (d === 0)
-        return;
-      if (_inChange)
-        return;
-      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
-      if (!newRole.trim() && typeof d.role !== "string")
-        return;
-      var membersToUpdate = d.members.filter(function(member) {
-        return member.role !== newRole;
-      });
-      if (membersToUpdate.length) {
-        _inChange = true;
-        context.perform(
-          function actionChangeMemberRoles(graph) {
-            membersToUpdate.forEach(function(member) {
-              var newMember = Object.assign({}, member, { role: newRole });
-              delete newMember.index;
-              graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
-            });
-            return graph;
-          },
-          _t("operations.change_role.annotation", {
-            n: membersToUpdate.length
-          })
-        );
-        context.validator().validate();
-      }
-      _inChange = false;
+      };
     }
-    function addMembership(d, role) {
-      this.blur();
-      _showBlank = false;
-      function actionAddMembers(relationId, ids, role2) {
-        return function(graph) {
-          for (var i2 in ids) {
-            var member = { id: ids[i2], type: graph.entity(ids[i2]).type, role: role2 };
-            graph = actionAddMember(relationId, member)(graph);
-          }
-          return graph;
-        };
-      }
-      if (d.relation) {
-        context.perform(
-          actionAddMembers(d.relation.id, _entityIDs, role),
-          _t("operations.add_member.annotation", {
-            n: _entityIDs.length
-          })
-        );
-        context.validator().validate();
-      } else {
-        var relation = osmRelation();
-        context.perform(
-          actionAddEntity(relation),
-          actionAddMembers(relation.id, _entityIDs, role),
-          _t("operations.add.annotation.relation")
-        );
-        context.enter(modeSelect(context, [relation.id]).newFeature(true));
+    defineRule("points", function isPoint(tags, geometry) {
+      return geometry === "point";
+    }, 200);
+    defineRule("traffic_roads", function isTrafficRoad(tags) {
+      return traffic_roads[tags.highway];
+    });
+    defineRule("service_roads", function isServiceRoad(tags) {
+      return service_roads[tags.highway];
+    });
+    defineRule("paths", function isPath(tags) {
+      return paths[tags.highway];
+    });
+    defineRule("buildings", function isBuilding(tags) {
+      return !!tags.building && tags.building !== "no" || tags.parking === "multi-storey" || tags.parking === "sheds" || tags.parking === "carports" || tags.parking === "garage_boxes";
+    }, 250);
+    defineRule("building_parts", function isBuildingPart(tags) {
+      return !!tags["building:part"];
+    });
+    defineRule("indoor", function isIndoor(tags) {
+      return !!tags.indoor;
+    });
+    defineRule("landuse", function isLanduse(tags, geometry) {
+      return geometry === "area" && (!!tags.landuse || !!tags.natural || !!tags.leisure || !!tags.amenity) && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
+    });
+    defineRule("boundaries", function isBoundary(tags, geometry) {
+      return (geometry === "line" && !!tags.boundary || geometry === "relation" && tags.type === "boundary") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway] || tags.waterway || tags.railway || tags.landuse || tags.natural || tags.building || tags.power);
+    });
+    defineRule("water", function isWater(tags) {
+      return !!tags.waterway || tags.natural === "water" || tags.natural === "coastline" || tags.natural === "bay" || tags.landuse === "pond" || tags.landuse === "basin" || tags.landuse === "reservoir" || tags.landuse === "salt_pond";
+    });
+    defineRule("rail", function isRail(tags) {
+      return (!!tags.railway || tags.landuse === "railway") && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
+    });
+    defineRule("pistes", function isPiste(tags) {
+      return tags["piste:type"];
+    });
+    defineRule("aerialways", function isAerialways(tags) {
+      return !!(tags == null ? void 0 : tags.aerialway) && tags.aerialway !== "yes" && tags.aerialway !== "station";
+    });
+    defineRule("power", function isPower(tags) {
+      return !!tags.power;
+    });
+    defineRule("past_future", function isPastFuture(tags) {
+      if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
+        return false;
       }
-    }
-    function deleteMembership(d3_event, d) {
-      this.blur();
-      if (d === 0)
-        return;
-      utilHighlightEntities([d.relation.id], false, context);
-      var indexes = d.members.map(function(member) {
-        return member.index;
-      });
-      context.perform(
-        actionDeleteMembers(d.relation.id, indexes),
-        _t("operations.delete_member.annotation", {
-          n: _entityIDs.length
-        })
-      );
-      context.validator().validate();
-    }
-    function fetchNearbyRelations(q, callback) {
-      var newRelation = {
-        relation: null,
-        value: _t("inspector.new_relation"),
-        display: _t.append("inspector.new_relation")
-      };
-      var entityID = _entityIDs[0];
-      var result = [];
-      var graph = context.graph();
-      function baseDisplayLabel(entity) {
-        var matched = _mainPresetIndex.match(entity, graph);
-        var presetName = matched && matched.name() || _t("inspector.relation");
-        var entityName = utilDisplayName(entity) || "";
-        return presetName + " " + entityName;
+      const keys2 = Object.keys(tags);
+      for (let i3 = 0; i3 < keys2.length; i3++) {
+        const key = keys2[i3];
+        const s2 = key.split(":")[0];
+        if (osmLifecyclePrefixes[s2] || osmLifecyclePrefixes[tags[key]]) return true;
       }
-      var explicitRelation = q && context.hasEntity(q.toLowerCase());
-      if (explicitRelation && explicitRelation.type === "relation" && explicitRelation.id !== entityID) {
-        result.push({
-          relation: explicitRelation,
-          value: baseDisplayLabel(explicitRelation) + " " + explicitRelation.id
-        });
-      } else {
-        context.history().intersects(context.map().extent()).forEach(function(entity) {
-          if (entity.type !== "relation" || entity.id === entityID)
-            return;
-          var value = baseDisplayLabel(entity);
-          if (q && (value + " " + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1)
-            return;
-          result.push({ relation: entity, value });
+      return false;
+    });
+    defineRule("others", function isOther(tags, geometry) {
+      return geometry === "line" || geometry === "area";
+    });
+    features.features = function() {
+      return _rules;
+    };
+    features.keys = function() {
+      return _keys;
+    };
+    features.enabled = function(k2) {
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return _rules[k3].enabled;
         });
-        result.sort(function(a, b) {
-          return osmRelation.creationOrder(a.relation, b.relation);
+      }
+      return _rules[k2] && _rules[k2].enabled;
+    };
+    features.disabled = function(k2) {
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return !_rules[k3].enabled;
         });
-        var dupeGroups = Object.values(utilArrayGroupBy(result, "value")).filter(function(v) {
-          return v.length > 1;
+      }
+      return _rules[k2] && !_rules[k2].enabled;
+    };
+    features.hidden = function(k2) {
+      var _a3;
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return _rules[k3].hidden();
         });
-        dupeGroups.forEach(function(group) {
-          group.forEach(function(obj) {
-            obj.value += " " + obj.relation.id;
-          });
+      }
+      return (_a3 = _rules[k2]) == null ? void 0 : _a3.hidden();
+    };
+    features.autoHidden = function(k2) {
+      if (!arguments.length) {
+        return _keys.filter(function(k3) {
+          return _rules[k3].autoHidden();
         });
       }
-      result.forEach(function(obj) {
-        obj.title = obj.value;
-      });
-      result.unshift(newRelation);
-      callback(result);
-    }
-    function renderDisclosureContent(selection2) {
-      var memberships = getMemberships();
-      var list = selection2.selectAll(".member-list").data([0]);
-      list = list.enter().append("ul").attr("class", "member-list").merge(list);
-      var items = list.selectAll("li.member-row-normal").data(memberships, function(d) {
-        return d.hash;
-      });
-      items.exit().each(unbind).remove();
-      var itemsEnter = items.enter().append("li").attr("class", "member-row member-row-normal form-field");
-      itemsEnter.on("mouseover", function(d3_event, d) {
-        utilHighlightEntities([d.relation.id], true, context);
-      }).on("mouseout", function(d3_event, d) {
-        utilHighlightEntities([d.relation.id], false, context);
-      });
-      var labelEnter = itemsEnter.append("label").attr("class", "field-label").attr("for", function(d) {
-        return d.domId;
-      });
-      var labelLink = labelEnter.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectRelation);
-      labelLink.append("span").attr("class", "member-entity-type").text(function(d) {
-        var matched = _mainPresetIndex.match(d.relation, context.graph());
-        return matched && matched.name() || _t.html("inspector.relation");
-      });
-      labelLink.append("span").attr("class", "member-entity-name").text(function(d) {
-        return utilDisplayName(d.relation);
-      });
-      labelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", deleteMembership);
-      labelEnter.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToRelation);
-      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
-      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d) {
-        return d.domId;
-      }).property("type", "text").property("value", function(d) {
-        return typeof d.role === "string" ? d.role : "";
-      }).attr("title", function(d) {
-        return Array.isArray(d.role) ? d.role.filter(Boolean).join("\n") : d.role;
-      }).attr("placeholder", function(d) {
-        return Array.isArray(d.role) ? _t("inspector.multiple_roles") : _t("inspector.role");
-      }).classed("mixed", function(d) {
-        return Array.isArray(d.role);
-      }).call(utilNoAuto).on("blur", changeRole).on("change", changeRole);
-      if (taginfo) {
-        wrapEnter.each(bindTypeahead);
+      return _rules[k2] && _rules[k2].autoHidden();
+    };
+    features.enable = function(k2) {
+      if (_rules[k2] && !_rules[k2].enabled) {
+        _rules[k2].enable();
+        update();
       }
-      var newMembership = list.selectAll(".member-row-new").data(_showBlank ? [0] : []);
-      newMembership.exit().remove();
-      var newMembershipEnter = newMembership.enter().append("li").attr("class", "member-row member-row-new form-field");
-      var newLabelEnter = newMembershipEnter.append("label").attr("class", "field-label");
-      newLabelEnter.append("input").attr("placeholder", _t("inspector.choose_relation")).attr("type", "text").attr("class", "member-entity-input").call(utilNoAuto);
-      newLabelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", function() {
-        list.selectAll(".member-row-new").remove();
-      });
-      var newWrapEnter = newMembershipEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
-      newWrapEnter.append("input").attr("class", "member-role").property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
-      newMembership = newMembership.merge(newMembershipEnter);
-      newMembership.selectAll(".member-entity-input").on("blur", cancelEntity).call(
-        nearbyCombo.on("accept", acceptEntity).on("cancel", cancelEntity)
-      );
-      var addRow = selection2.selectAll(".add-row").data([0]);
-      var addRowEnter = addRow.enter().append("div").attr("class", "add-row");
-      var addRelationButton = addRowEnter.append("button").attr("class", "add-relation").attr("aria-label", _t("inspector.add_to_relation"));
-      addRelationButton.call(svgIcon("#iD-icon-plus", "light"));
-      addRelationButton.call(uiTooltip().title(() => _t.append("inspector.add_to_relation")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left"));
-      addRowEnter.append("div").attr("class", "space-value");
-      addRowEnter.append("div").attr("class", "space-buttons");
-      addRow = addRow.merge(addRowEnter);
-      addRow.select(".add-relation").on("click", function() {
-        _showBlank = true;
-        section.reRender();
-        list.selectAll(".member-entity-input").node().focus();
-      });
-      function acceptEntity(d) {
-        if (!d) {
-          cancelEntity();
-          return;
+    };
+    features.enableAll = function() {
+      var didEnable = false;
+      for (var k2 in _rules) {
+        if (!_rules[k2].enabled) {
+          didEnable = true;
+          _rules[k2].enable();
         }
-        if (d.relation)
-          utilHighlightEntities([d.relation.id], false, context);
-        var role = context.cleanRelationRole(list.selectAll(".member-row-new .member-role").property("value"));
-        addMembership(d, role);
       }
-      function cancelEntity() {
-        var input = newMembership.selectAll(".member-entity-input");
-        input.property("value", "");
-        context.surface().selectAll(".highlighted").classed("highlighted", false);
+      if (didEnable) update();
+    };
+    features.disable = function(k2) {
+      if (_rules[k2] && _rules[k2].enabled) {
+        _rules[k2].disable();
+        update();
       }
-      function bindTypeahead(d) {
-        var row = select_default2(this);
-        var role = row.selectAll("input.member-role");
-        var origValue = role.property("value");
-        function sort(value, data) {
-          var sameletter = [];
-          var other = [];
-          for (var i2 = 0; i2 < data.length; i2++) {
-            if (data[i2].value.substring(0, value.length) === value) {
-              sameletter.push(data[i2]);
-            } else {
-              other.push(data[i2]);
-            }
-          }
-          return sameletter.concat(other);
+    };
+    features.disableAll = function() {
+      var didDisable = false;
+      for (var k2 in _rules) {
+        if (_rules[k2].enabled) {
+          didDisable = true;
+          _rules[k2].disable();
         }
-        role.call(
-          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
-            var rtype = d.relation.tags.type;
-            taginfo.roles({
-              debounce: true,
-              rtype: rtype || "",
-              geometry: context.graph().geometry(_entityIDs[0]),
-              query: role2
-            }, function(err, data) {
-              if (!err)
-                callback(sort(role2, data));
-            });
-          }).on("cancel", function() {
-            role.property("value", origValue);
-          })
-        );
       }
-      function unbind() {
-        var row = select_default2(this);
-        row.selectAll("input.member-role").call(uiCombobox.off, context);
+      if (didDisable) update();
+    };
+    features.toggle = function(k2) {
+      if (_rules[k2]) {
+        (function(f2) {
+          return f2.enabled ? f2.disable() : f2.enable();
+        })(_rules[k2]);
+        update();
       }
-    }
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _showBlank = false;
-      return section;
     };
-    return section;
-  }
-
-  // modules/ui/sections/selection_list.js
-  function uiSectionSelectionList(context) {
-    var _selectedIDs = [];
-    var section = uiSection("selected-features", context).shouldDisplay(function() {
-      return _selectedIDs.length > 1;
-    }).label(function() {
-      return _t.append("inspector.title_count", { title: _t("inspector.features"), count: _selectedIDs.length });
-    }).disclosureContent(renderDisclosureContent);
-    context.history().on("change.selectionList", function(difference) {
-      if (difference) {
-        section.reRender();
+    features.resetStats = function() {
+      for (var i3 = 0; i3 < _keys.length; i3++) {
+        _rules[_keys[i3]].count = 0;
       }
-    });
-    section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _selectedIDs;
-      _selectedIDs = val;
-      return section;
+      dispatch14.call("change");
     };
-    function selectEntity(d3_event, entity) {
-      context.enter(modeSelect(context, [entity.id]));
-    }
-    function deselectEntity(d3_event, entity) {
-      var selectedIDs = _selectedIDs.slice();
-      var index = selectedIDs.indexOf(entity.id);
-      if (index > -1) {
-        selectedIDs.splice(index, 1);
-        context.enter(modeSelect(context, selectedIDs));
+    features.gatherStats = function(d2, resolver, dimensions) {
+      var needsRedraw = false;
+      var types = utilArrayGroupBy(d2, "type");
+      var entities = [].concat(types.relation || [], types.way || [], types.node || []);
+      var currHidden, geometry, matches, i3, j2;
+      for (i3 = 0; i3 < _keys.length; i3++) {
+        _rules[_keys[i3]].count = 0;
       }
-    }
-    function renderDisclosureContent(selection2) {
-      var list = selection2.selectAll(".feature-list").data([0]);
-      list = list.enter().append("ul").attr("class", "feature-list").merge(list);
-      var entities = _selectedIDs.map(function(id2) {
-        return context.hasEntity(id2);
-      }).filter(Boolean);
-      var items = list.selectAll(".feature-list-item").data(entities, osmEntity.key);
-      items.exit().remove();
-      var enter = items.enter().append("li").attr("class", "feature-list-item").each(function(d) {
-        select_default2(this).on("mouseover", function() {
-          utilHighlightEntities([d.id], true, context);
-        }).on("mouseout", function() {
-          utilHighlightEntities([d.id], false, context);
-        });
-      });
-      var label = enter.append("button").attr("class", "label").on("click", selectEntity);
-      label.append("span").attr("class", "entity-geom-icon").call(svgIcon("", "pre-text"));
-      label.append("span").attr("class", "entity-type");
-      label.append("span").attr("class", "entity-name");
-      enter.append("button").attr("class", "close").attr("title", _t("icons.deselect")).on("click", deselectEntity).call(svgIcon("#iD-icon-close"));
-      items = items.merge(enter);
-      items.selectAll(".entity-geom-icon use").attr("href", function() {
-        var entity = this.parentNode.parentNode.__data__;
-        return "#iD-icon-" + entity.geometry(context.graph());
-      });
-      items.selectAll(".entity-type").text(function(entity) {
-        return _mainPresetIndex.match(entity, context.graph()).name();
-      });
-      items.selectAll(".entity-name").text(function(d) {
-        var entity = context.entity(d.id);
-        return utilDisplayName(entity);
-      });
-    }
-    return section;
-  }
-
-  // modules/ui/entity_editor.js
-  function uiEntityEditor(context) {
-    var dispatch10 = dispatch_default("choose");
-    var _state = "select";
-    var _coalesceChanges = false;
-    var _modified = false;
-    var _base;
-    var _entityIDs;
-    var _activePresets = [];
-    var _newFeature;
-    var _sections;
-    function entityEditor(selection2) {
-      var combinedTags = utilCombinedTags(_entityIDs, context.graph());
-      var header = selection2.selectAll(".header").data([0]);
-      var headerEnter = header.enter().append("div").attr("class", "header fillL");
-      var direction = _mainLocalizer.textDirection() === "rtl" ? "forward" : "backward";
-      headerEnter.append("button").attr("class", "preset-reset preset-choose").attr("title", _t(`icons.${direction}`)).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"));
-      headerEnter.append("h2");
-      header = header.merge(headerEnter);
-      header.selectAll("h2").text("").call(_entityIDs.length === 1 ? _t.append("inspector.edit") : _t.append("inspector.edit_features"));
-      header.selectAll(".preset-reset").on("click", function() {
-        dispatch10.call("choose", this, _activePresets);
-      });
-      var body = selection2.selectAll(".inspector-body").data([0]);
-      var bodyEnter = body.enter().append("div").attr("class", "entity-editor inspector-body sep-top");
-      body = body.merge(bodyEnter);
-      if (!_sections) {
-        _sections = [
-          uiSectionSelectionList(context),
-          uiSectionFeatureType(context).on("choose", function(presets) {
-            dispatch10.call("choose", this, presets);
-          }),
-          uiSectionEntityIssues(context),
-          uiSectionPresetFields(context).on("change", changeTags).on("revert", revertTags),
-          uiSectionRawTagEditor("raw-tag-editor", context).on("change", changeTags),
-          uiSectionRawMemberEditor(context),
-          uiSectionRawMembershipEditor(context)
-        ];
-      }
-      _sections.forEach(function(section) {
-        if (section.entityIDs) {
-          section.entityIDs(_entityIDs);
-        }
-        if (section.presets) {
-          section.presets(_activePresets);
-        }
-        if (section.tags) {
-          section.tags(combinedTags);
-        }
-        if (section.state) {
-          section.state(_state);
-        }
-        body.call(section.render);
-      });
-      context.history().on("change.entity-editor", historyChanged);
-      function historyChanged(difference) {
-        if (selection2.selectAll(".entity-editor").empty())
-          return;
-        if (_state === "hide")
-          return;
-        var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
-        if (!significant)
-          return;
-        _entityIDs = _entityIDs.filter(context.hasEntity);
-        if (!_entityIDs.length)
-          return;
-        var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
-        loadActivePresets();
-        var graph = context.graph();
-        entityEditor.modified(_base !== graph);
-        entityEditor(selection2);
-        if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
-          context.container().selectAll(".entity-editor button.preset-reset .label").style("background-color", "#fff").transition().duration(750).style("background-color", null);
-        }
-      }
-    }
-    function changeTags(entityIDs, changed, onInput) {
-      var actions = [];
-      for (var i2 in entityIDs) {
-        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 (!onInput) {
-          tags = utilCleanTags(tags);
-        }
-        if (!(0, import_fast_deep_equal10.default)(entity.tags, tags)) {
-          actions.push(actionChangeTags(entityID, tags));
-        }
-      }
-      if (actions.length) {
-        var combinedAction = function(graph) {
-          actions.forEach(function(action) {
-            graph = action(graph);
-          });
-          return graph;
-        };
-        var annotation = _t("operations.change_tags.annotation");
-        if (_coalesceChanges) {
-          context.overwrite(combinedAction, annotation);
-        } else {
-          context.perform(combinedAction, annotation);
-          _coalesceChanges = !!onInput;
-        }
-      }
-      if (!onInput) {
-        context.validator().validate();
-      }
-    }
-    function revertTags(keys) {
-      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];
-          changed[key] = original ? original.tags[key] : void 0;
-        }
-        var entity = context.entity(entityID);
-        var tags = Object.assign({}, entity.tags);
-        for (var k in changed) {
-          if (!k)
-            continue;
-          var v = changed[k];
-          if (v !== void 0 || tags.hasOwnProperty(k)) {
-            tags[k] = v;
-          }
-        }
-        tags = utilCleanTags(tags);
-        if (!(0, import_fast_deep_equal10.default)(entity.tags, tags)) {
-          actions.push(actionChangeTags(entityID, tags));
+      _cullFactor = dimensions[0] * dimensions[1] / 1e6;
+      for (i3 = 0; i3 < entities.length; i3++) {
+        geometry = entities[i3].geometry(resolver);
+        matches = Object.keys(features.getMatches(entities[i3], resolver, geometry));
+        for (j2 = 0; j2 < matches.length; j2++) {
+          _rules[matches[j2]].count++;
         }
       }
-      if (actions.length) {
-        var combinedAction = function(graph) {
-          actions.forEach(function(action) {
-            graph = action(graph);
-          });
-          return graph;
-        };
-        var annotation = _t("operations.change_tags.annotation");
-        if (_coalesceChanges) {
-          context.overwrite(combinedAction, annotation);
-        } else {
-          context.perform(combinedAction, annotation);
-          _coalesceChanges = false;
-        }
+      currHidden = features.hidden();
+      if (currHidden !== _hidden) {
+        _hidden = currHidden;
+        needsRedraw = true;
+        dispatch14.call("change");
       }
-      context.validator().validate();
-    }
-    entityEditor.modified = function(val) {
-      if (!arguments.length)
-        return _modified;
-      _modified = val;
-      return entityEditor;
+      return needsRedraw;
     };
-    entityEditor.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      return entityEditor;
+    features.stats = function() {
+      for (var i3 = 0; i3 < _keys.length; i3++) {
+        _stats[_keys[i3]] = _rules[_keys[i3]].count;
+      }
+      return _stats;
     };
-    entityEditor.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _base = context.graph();
-      _coalesceChanges = false;
-      if (val && _entityIDs && utilArrayIdentical(_entityIDs, val))
-        return entityEditor;
-      _entityIDs = val;
-      loadActivePresets(true);
-      return entityEditor.modified(false);
+    features.clear = function(d2) {
+      for (var i3 = 0; i3 < d2.length; i3++) {
+        features.clearEntity(d2[i3]);
+      }
     };
-    entityEditor.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
-      _newFeature = val;
-      return entityEditor;
+    features.clearEntity = function(entity) {
+      delete _cache5[osmEntity.key(entity)];
     };
-    function loadActivePresets(isForNewSelection) {
-      var graph = context.graph();
-      var counts = {};
-      for (var i2 in _entityIDs) {
-        var entity = graph.hasEntity(_entityIDs[i2]);
-        if (!entity)
-          return;
-        var match = _mainPresetIndex.match(entity, graph);
-        if (!counts[match.id])
-          counts[match.id] = 0;
-        counts[match.id] += 1;
-      }
-      var matches = Object.keys(counts).sort(function(p1, p2) {
-        return counts[p2] - counts[p1];
-      }).map(function(pID) {
-        return _mainPresetIndex.item(pID);
+    features.reset = function() {
+      Array.from(_deferred2).forEach(function(handle) {
+        window.cancelIdleCallback(handle);
+        _deferred2.delete(handle);
       });
-      if (!isForNewSelection) {
-        var weakPreset = _activePresets.length === 1 && !_activePresets[0].isFallback() && Object.keys(_activePresets[0].addTags || {}).length === 0;
-        if (weakPreset && matches.length === 1 && matches[0].isFallback())
-          return;
-      }
-      entityEditor.presets(matches);
+      _cache5 = {};
+    };
+    function relationShouldBeChecked(relation) {
+      return relation.tags.type === "boundary";
     }
-    entityEditor.presets = function(val) {
-      if (!arguments.length)
-        return _activePresets;
-      if (!utilArrayIdentical(val, _activePresets)) {
-        _activePresets = val;
+    features.getMatches = function(entity, resolver, geometry) {
+      if (geometry === "vertex" || geometry === "relation" && !relationShouldBeChecked(entity)) return {};
+      var ent = osmEntity.key(entity);
+      if (!_cache5[ent]) {
+        _cache5[ent] = {};
       }
-      return entityEditor;
+      if (!_cache5[ent].matches) {
+        var matches = {};
+        var hasMatch = false;
+        for (var i3 = 0; i3 < _keys.length; i3++) {
+          if (_keys[i3] === "others") {
+            if (hasMatch) continue;
+            if (entity.type === "way") {
+              var parents = features.getParents(entity, resolver, geometry);
+              if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
+              parents.length > 0 && parents.every(function(parent) {
+                return parent.tags.type === "boundary";
+              })) {
+                var pkey = osmEntity.key(parents[0]);
+                if (_cache5[pkey] && _cache5[pkey].matches) {
+                  matches = Object.assign({}, _cache5[pkey].matches);
+                  continue;
+                }
+              }
+            }
+          }
+          if (_rules[_keys[i3]].filter(entity.tags, geometry)) {
+            matches[_keys[i3]] = hasMatch = true;
+          }
+        }
+        _cache5[ent].matches = matches;
+      }
+      return _cache5[ent].matches;
     };
-    return utilRebind(entityEditor, dispatch10, "on");
-  }
-
-  // modules/ui/feature_list.js
-  var sexagesimal = __toESM(require_sexagesimal());
-  function uiFeatureList(context) {
-    var _geocodeResults;
-    function featureList(selection2) {
-      var header = selection2.append("div").attr("class", "header fillL");
-      header.append("h2").call(_t.append("inspector.feature_list"));
-      var searchWrap = selection2.append("div").attr("class", "search-header");
-      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
-      var search = searchWrap.append("input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keypress", keypress).on("keydown", keydown).on("input", inputevent);
-      var listWrap = selection2.append("div").attr("class", "inspector-body");
-      var list = listWrap.append("div").attr("class", "feature-list");
-      context.on("exit.feature-list", clearSearch);
-      context.map().on("drawn.feature-list", mapDrawn);
-      context.keybinding().on(uiCmd("\u2318F"), focusSearch);
-      function focusSearch(d3_event) {
-        var mode = context.mode() && context.mode().id;
-        if (mode !== "browse")
-          return;
-        d3_event.preventDefault();
-        search.node().focus();
+    features.getParents = function(entity, resolver, geometry) {
+      if (geometry === "point") return [];
+      var ent = osmEntity.key(entity);
+      if (!_cache5[ent]) {
+        _cache5[ent] = {};
       }
-      function keydown(d3_event) {
-        if (d3_event.keyCode === 27) {
-          search.node().blur();
+      if (!_cache5[ent].parents) {
+        var parents = [];
+        if (geometry === "vertex") {
+          parents = resolver.parentWays(entity);
+        } else {
+          parents = resolver.parentRelations(entity);
         }
+        _cache5[ent].parents = parents;
       }
-      function keypress(d3_event) {
-        var q = search.property("value"), items = list.selectAll(".feature-list-item");
-        if (d3_event.keyCode === 13 && q.length && items.size()) {
-          click(d3_event, items.datum());
+      return _cache5[ent].parents;
+    };
+    features.isHiddenPreset = function(preset, geometry) {
+      if (!_hidden.length) return false;
+      if (!preset.tags) return false;
+      var test = preset.setTags({}, geometry);
+      for (var key in _rules) {
+        if (_rules[key].filter(test, geometry)) {
+          if (_hidden.indexOf(key) !== -1) {
+            return key;
+          }
+          return false;
         }
       }
-      function inputevent() {
-        _geocodeResults = void 0;
-        drawList();
+      return false;
+    };
+    features.isHiddenFeature = function(entity, resolver, geometry) {
+      if (!_hidden.length) return false;
+      if (!entity.version) return false;
+      if (_forceVisible[entity.id]) return false;
+      var matches = Object.keys(features.getMatches(entity, resolver, geometry));
+      return matches.length && matches.every(function(k2) {
+        return features.hidden(k2);
+      });
+    };
+    features.isHiddenChild = function(entity, resolver, geometry) {
+      if (!_hidden.length) return false;
+      if (!entity.version || geometry === "point") return false;
+      if (_forceVisible[entity.id]) return false;
+      var parents = features.getParents(entity, resolver, geometry);
+      if (!parents.length) return false;
+      for (var i3 = 0; i3 < parents.length; i3++) {
+        if (!features.isHidden(parents[i3], resolver, parents[i3].geometry(resolver))) {
+          return false;
+        }
       }
-      function clearSearch() {
-        search.property("value", "");
-        drawList();
+      return true;
+    };
+    features.hasHiddenConnections = function(entity, resolver) {
+      if (!_hidden.length) return false;
+      var childNodes, connections;
+      if (entity.type === "midpoint") {
+        childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
+        connections = [];
+      } else {
+        childNodes = entity.nodes ? resolver.childNodes(entity) : [];
+        connections = features.getParents(entity, resolver, entity.geometry(resolver));
       }
-      function mapDrawn(e) {
-        if (e.full) {
-          drawList();
+      connections = childNodes.reduce(function(result, e3) {
+        return resolver.isShared(e3) ? utilArrayUnion(result, resolver.parentWays(e3)) : result;
+      }, connections);
+      return connections.some(function(e3) {
+        return features.isHidden(e3, resolver, e3.geometry(resolver));
+      });
+    };
+    features.isHidden = function(entity, resolver, geometry) {
+      if (!_hidden.length) return false;
+      if (!entity.version) return false;
+      var fn = geometry === "vertex" ? features.isHiddenChild : features.isHiddenFeature;
+      return fn(entity, resolver, geometry);
+    };
+    features.filter = function(d2, resolver) {
+      if (!_hidden.length) return d2;
+      var result = [];
+      for (var i3 = 0; i3 < d2.length; i3++) {
+        var entity = d2[i3];
+        if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
+          result.push(entity);
         }
       }
-      function features2() {
-        var result = [];
-        var graph = context.graph();
-        var visibleCenter = context.map().extent().center();
-        var q = search.property("value").toLowerCase();
-        if (!q)
-          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])];
-          result.push({
-            id: -1,
-            geometry: "point",
-            type: _t("inspector.location"),
-            name: dmsCoordinatePair([loc[1], loc[0]]),
-            location: loc
-          });
-        }
-        var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
-        if (idMatch) {
-          var elemType = idMatch[1].charAt(0);
-          var elemId = idMatch[2];
-          result.push({
-            id: elemType + elemId,
-            geometry: elemType === "n" ? "point" : elemType === "w" ? "line" : "relation",
-            type: elemType === "n" ? _t("inspector.node") : elemType === "w" ? _t("inspector.way") : _t("inspector.relation"),
-            name: elemId
-          });
-        }
-        var allEntities = graph.entities;
-        var localResults = [];
-        for (var id2 in allEntities) {
-          var entity = allEntities[id2];
-          if (!entity)
-            continue;
-          var name = utilDisplayName(entity) || "";
-          if (name.toLowerCase().indexOf(q) < 0)
-            continue;
-          var matched = _mainPresetIndex.match(entity, graph);
-          var type3 = 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,
-            name,
-            distance
-          });
-          if (localResults.length > 100)
-            break;
-        }
-        localResults = localResults.sort(function byDistance(a, b) {
-          return a.distance - b.distance;
-        });
-        result = result.concat(localResults);
-        (_geocodeResults || []).forEach(function(d) {
-          if (d.osm_type && d.osm_id) {
-            var id3 = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
-            var tags = {};
-            tags[d.class] = d.type;
-            var attrs = { id: id3, type: d.osm_type, tags };
-            if (d.osm_type === "way") {
-              attrs.nodes = ["a", "a"];
-            }
-            var tempEntity = osmEntity(attrs);
-            var tempGraph = coreGraph([tempEntity]);
-            var matched2 = _mainPresetIndex.match(tempEntity, tempGraph);
-            var type4 = matched2 && matched2.name() || utilDisplayType(id3);
-            result.push({
-              id: tempEntity.id,
-              geometry: tempEntity.geometry(tempGraph),
-              type: type4,
-              name: d.display_name,
-              extent: new geoExtent(
-                [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
-                [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])]
-              )
-            });
+      return result;
+    };
+    features.forceVisible = function(entityIDs) {
+      if (!arguments.length) return Object.keys(_forceVisible);
+      _forceVisible = {};
+      for (var i3 = 0; i3 < entityIDs.length; i3++) {
+        _forceVisible[entityIDs[i3]] = true;
+        var entity = context.hasEntity(entityIDs[i3]);
+        if (entity && entity.type === "relation") {
+          for (var j2 in entity.members) {
+            _forceVisible[entity.members[j2].id] = true;
           }
-        });
-        if (q.match(/^[0-9]+$/)) {
-          result.push({
-            id: "n" + q,
-            geometry: "point",
-            type: _t("inspector.node"),
-            name: q
-          });
-          result.push({
-            id: "w" + q,
-            geometry: "line",
-            type: _t("inspector.way"),
-            name: q
-          });
-          result.push({
-            id: "r" + q,
-            geometry: "relation",
-            type: _t("inspector.relation"),
-            name: q
-          });
-        }
-        return result;
-      }
-      function drawList() {
-        var value = search.property("value");
-        var results = features2();
-        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");
-        list.selectAll(".no-results-item .entity-name").html("").call(_t.append("geocoder.no_results_worldwide"));
-        if (services.geocoder) {
-          list.selectAll(".geocode-item").data([0]).enter().append("button").attr("class", "geocode-item secondary-action").on("click", geocoderSearch).append("div").attr("class", "label").append("span").attr("class", "entity-name").call(_t.append("geocoder.search"));
         }
-        list.selectAll(".no-results-item").style("display", value.length && !results.length ? "block" : "none");
-        list.selectAll(".geocode-item").style("display", value && _geocodeResults === void 0 ? "block" : "none");
-        list.selectAll(".feature-list-item").data([-1]).remove();
-        var items = list.selectAll(".feature-list-item").data(results, function(d) {
-          return d.id;
-        });
-        var enter = items.enter().insert("button", ".geocode-item").attr("class", "feature-list-item").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
-        var label = enter.append("div").attr("class", "label");
-        label.each(function(d) {
-          select_default2(this).call(svgIcon("#iD-icon-" + d.geometry, "pre-text"));
-        });
-        label.append("span").attr("class", "entity-type").text(function(d) {
-          return d.type;
-        });
-        label.append("span").attr("class", "entity-name").text(function(d) {
-          return d.name;
-        });
-        enter.style("opacity", 0).transition().style("opacity", 1);
-        items.order();
-        items.exit().remove();
       }
-      function mouseover(d3_event, d) {
-        if (d.id === -1)
-          return;
-        utilHighlightEntities([d.id], true, context);
+      return features;
+    };
+    features.init = function() {
+      var storage = corePreferences("disabled-features");
+      if (storage) {
+        var storageDisabled = storage.replace(/;/g, ",").split(",");
+        storageDisabled.forEach(features.disable);
       }
-      function mouseout(d3_event, d) {
-        if (d.id === -1)
-          return;
-        utilHighlightEntities([d.id], false, context);
+      var hash = utilStringQs(window.location.hash);
+      if (hash.disable_features) {
+        var hashDisabled = hash.disable_features.replace(/;/g, ",").split(",");
+        hashDisabled.forEach(features.disable);
       }
-      function click(d3_event, d) {
-        d3_event.preventDefault();
-        if (d.location) {
-          context.map().centerZoomEase([d.location[1], d.location[0]], 19);
-        } else if (d.entity) {
-          utilHighlightEntities([d.id], false, context);
-          context.enter(modeSelect(context, [d.entity.id]));
-          context.map().zoomToEase(d.entity);
-        } else {
-          context.zoomToEntity(d.id);
+    };
+    context.history().on("merge.features", function(newEntities) {
+      if (!newEntities) return;
+      var handle = window.requestIdleCallback(function() {
+        var graph = context.graph();
+        var types = utilArrayGroupBy(newEntities, "type");
+        var entities = [].concat(types.relation || [], types.way || [], types.node || []);
+        for (var i3 = 0; i3 < entities.length; i3++) {
+          var geometry = entities[i3].geometry(graph);
+          features.getMatches(entities[i3], graph, geometry);
         }
-      }
-      function geocoderSearch() {
-        services.geocoder.search(search.property("value"), function(err, resp) {
-          _geocodeResults = resp || [];
-          drawList();
-        });
-      }
+      });
+      _deferred2.add(handle);
+    });
+    return features;
+  }
+
+  // modules/util/bind_once.js
+  function utilBindOnce(target, type2, listener, capture) {
+    var typeOnce = type2 + ".once";
+    function one2() {
+      target.on(typeOnce, null);
+      listener.apply(this, arguments);
     }
-    return featureList;
+    target.on(typeOnce, one2, capture);
+    return this;
   }
 
-  // modules/ui/improveOSM_comments.js
-  function uiImproveOsmComments() {
-    let _qaItem;
-    function issueComments(selection2) {
-      let comments = selection2.selectAll(".comments-container").data([0]);
-      comments = comments.enter().append("div").attr("class", "comments-container").merge(comments);
-      services.improveOSM.getComments(_qaItem).then((d) => {
-        if (!d.comments)
-          return;
-        const commentEnter = comments.selectAll(".comment").data(d.comments).enter().append("div").attr("class", "comment");
-        commentEnter.append("div").attr("class", "comment-avatar").call(svgIcon("#iD-icon-avatar", "comment-avatar-icon"));
-        const mainEnter = commentEnter.append("div").attr("class", "comment-main");
-        const metadataEnter = mainEnter.append("div").attr("class", "comment-metadata");
-        metadataEnter.append("div").attr("class", "comment-author").each(function(d2) {
-          const osm = services.osm;
-          let selection3 = select_default2(this);
-          if (osm && d2.username) {
-            selection3 = selection3.append("a").attr("class", "comment-author-link").attr("href", osm.userURL(d2.username)).attr("target", "_blank");
-          }
-          selection3.text((d4) => d4.username);
+  // modules/util/zoom_pan.js
+  function defaultFilter3(d3_event) {
+    return !d3_event.ctrlKey && !d3_event.button;
+  }
+  function defaultExtent2() {
+    var e3 = this;
+    if (e3 instanceof SVGElement) {
+      e3 = e3.ownerSVGElement || e3;
+      if (e3.hasAttribute("viewBox")) {
+        e3 = e3.viewBox.baseVal;
+        return [[e3.x, e3.y], [e3.x + e3.width, e3.y + e3.height]];
+      }
+      return [[0, 0], [e3.width.baseVal.value, e3.height.baseVal.value]];
+    }
+    return [[0, 0], [e3.clientWidth, e3.clientHeight]];
+  }
+  function defaultWheelDelta2(d3_event) {
+    return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 2e-3);
+  }
+  function defaultConstrain2(transform2, extent, translateExtent) {
+    var dx0 = transform2.invertX(extent[0][0]) - translateExtent[0][0], dx1 = transform2.invertX(extent[1][0]) - translateExtent[1][0], dy0 = transform2.invertY(extent[0][1]) - translateExtent[0][1], dy1 = transform2.invertY(extent[1][1]) - translateExtent[1][1];
+    return transform2.translate(
+      dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
+      dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
+    );
+  }
+  function utilZoomPan() {
+    var filter2 = defaultFilter3, extent = defaultExtent2, constrain = defaultConstrain2, wheelDelta = defaultWheelDelta2, scaleExtent = [0, Infinity], translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], interpolate = zoom_default, dispatch14 = dispatch_default("start", "zoom", "end"), _wheelDelay = 150, _transform = identity2, _activeGesture;
+    function zoom(selection2) {
+      selection2.on("pointerdown.zoom", pointerdown).on("wheel.zoom", wheeled).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
+      select_default2(window).on("pointermove.zoompan", pointermove).on("pointerup.zoompan pointercancel.zoompan", pointerup);
+    }
+    zoom.transform = function(collection, transform2, point) {
+      var selection2 = collection.selection ? collection.selection() : collection;
+      if (collection !== selection2) {
+        schedule(collection, transform2, point);
+      } else {
+        selection2.interrupt().each(function() {
+          gesture(this, arguments).start(null).zoom(null, null, typeof transform2 === "function" ? transform2.apply(this, arguments) : transform2).end(null);
         });
-        metadataEnter.append("div").attr("class", "comment-date").html((d2) => _t.html("note.status.commented", { when: localeDateString2(d2.timestamp) }));
-        mainEnter.append("div").attr("class", "comment-text").append("p").text((d2) => d2.text);
-      }).catch((err) => {
-        console.log(err);
+      }
+    };
+    zoom.scaleBy = function(selection2, k2, p2) {
+      zoom.scaleTo(selection2, function() {
+        var k0 = _transform.k, k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
+        return k0 * k1;
+      }, p2);
+    };
+    zoom.scaleTo = function(selection2, k2, p2) {
+      zoom.transform(selection2, function() {
+        var e3 = extent.apply(this, arguments), t0 = _transform, p02 = !p2 ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2, p1 = t0.invert(p02), k1 = typeof k2 === "function" ? k2.apply(this, arguments) : k2;
+        return constrain(translate(scale(t0, k1), p02, p1), e3, translateExtent);
+      }, p2);
+    };
+    zoom.translateBy = function(selection2, x2, y2) {
+      zoom.transform(selection2, function() {
+        return constrain(_transform.translate(
+          typeof x2 === "function" ? x2.apply(this, arguments) : x2,
+          typeof y2 === "function" ? y2.apply(this, arguments) : y2
+        ), extent.apply(this, arguments), translateExtent);
       });
+    };
+    zoom.translateTo = function(selection2, x2, y2, p2) {
+      zoom.transform(selection2, function() {
+        var e3 = extent.apply(this, arguments), t2 = _transform, p02 = !p2 ? centroid(e3) : typeof p2 === "function" ? p2.apply(this, arguments) : p2;
+        return constrain(identity2.translate(p02[0], p02[1]).scale(t2.k).translate(
+          typeof x2 === "function" ? -x2.apply(this, arguments) : -x2,
+          typeof y2 === "function" ? -y2.apply(this, arguments) : -y2
+        ), e3, translateExtent);
+      }, p2);
+    };
+    function scale(transform2, k2) {
+      k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k2));
+      return k2 === transform2.k ? transform2 : new Transform(k2, transform2.x, transform2.y);
     }
-    function localeDateString2(s) {
-      if (!s)
-        return null;
-      const options2 = { day: "numeric", month: "short", year: "numeric" };
-      const d = new Date(s * 1e3);
-      if (isNaN(d.getTime()))
-        return null;
-      return d.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+    function translate(transform2, p02, p1) {
+      var x2 = p02[0] - p1[0] * transform2.k, y2 = p02[1] - p1[1] * transform2.k;
+      return x2 === transform2.x && y2 === transform2.y ? transform2 : new Transform(transform2.k, x2, y2);
     }
-    issueComments.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return issueComments;
-    };
-    return issueComments;
-  }
-
-  // modules/ui/improveOSM_details.js
-  function uiImproveOsmDetails(context) {
-    let _qaItem;
-    function issueDetail(d) {
-      if (d.desc)
-        return d.desc;
-      const issueKey = d.issueKey;
-      d.replacements = d.replacements || {};
-      d.replacements.default = { html: _t.html("inspector.unknown") };
-      return _t.html(`QA.improveOSM.error_types.${issueKey}.description`, d.replacements);
-    }
-    function improveOsmDetails(selection2) {
-      const details = selection2.selectAll(".error-details").data(
-        _qaItem ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      details.exit().remove();
-      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
-      const descriptionEnter = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      descriptionEnter.append("h4").call(_t.append("QA.keepRight.detail_description"));
-      descriptionEnter.append("div").attr("class", "qa-details-description-text").html(issueDetail);
-      let relatedEntities = [];
-      descriptionEnter.selectAll(".error_entity_link, .error_object_link").attr("href", "#").each(function() {
-        const link2 = select_default2(this);
-        const isObjectLink = link2.classed("error_object_link");
-        const entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
-        const entity = context.hasEntity(entityID);
-        relatedEntities.push(entityID);
-        link2.on("mouseenter", () => {
-          utilHighlightEntities([entityID], true, context);
-        }).on("mouseleave", () => {
-          utilHighlightEntities([entityID], false, context);
-        }).on("click", (d3_event) => {
-          d3_event.preventDefault();
-          utilHighlightEntities([entityID], false, context);
-          const osmlayer = context.layers().layer("osm");
-          if (!osmlayer.enabled()) {
-            osmlayer.enabled(true);
-          }
-          context.map().centerZoom(_qaItem.loc, 20);
-          if (entity) {
-            context.enter(modeSelect(context, [entityID]));
+    function centroid(extent2) {
+      return [(+extent2[0][0] + +extent2[1][0]) / 2, (+extent2[0][1] + +extent2[1][1]) / 2];
+    }
+    function schedule(transition2, transform2, point) {
+      transition2.on("start.zoom", function() {
+        gesture(this, arguments).start(null);
+      }).on("interrupt.zoom end.zoom", function() {
+        gesture(this, arguments).end(null);
+      }).tween("zoom", function() {
+        var that = this, args = arguments, g3 = gesture(that, args), e3 = extent.apply(that, args), p2 = !point ? centroid(e3) : typeof point === "function" ? point.apply(that, args) : point, w2 = Math.max(e3[1][0] - e3[0][0], e3[1][1] - e3[0][1]), a2 = _transform, b2 = typeof transform2 === "function" ? transform2.apply(that, args) : transform2, i3 = interpolate(a2.invert(p2).concat(w2 / a2.k), b2.invert(p2).concat(w2 / b2.k));
+        return function(t2) {
+          if (t2 === 1) {
+            t2 = b2;
           } else {
-            context.loadEntity(entityID, (err, result) => {
-              if (err)
-                return;
-              const entity2 = result.data.find((e) => e.id === entityID);
-              if (entity2)
-                context.enter(modeSelect(context, [entityID]));
-            });
-          }
-        });
-        if (entity) {
-          let name = utilDisplayName(entity);
-          if (!name && !isObjectLink) {
-            const preset = _mainPresetIndex.match(entity, context.graph());
-            name = preset && !preset.isFallback() && preset.name();
-          }
-          if (name) {
-            this.innerText = name;
+            var l2 = i3(t2);
+            var k2 = w2 / l2[2];
+            t2 = new Transform(k2, p2[0] - l2[0] * k2, p2[1] - l2[1] * k2);
           }
-        }
+          g3.zoom(null, null, t2);
+        };
       });
-      context.features().forceVisible(relatedEntities);
-      context.map().pan([0, 0]);
     }
-    improveOsmDetails.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return improveOsmDetails;
-    };
-    return improveOsmDetails;
-  }
-
-  // modules/ui/improveOSM_header.js
-  function uiImproveOsmHeader() {
-    let _qaItem;
-    function issueTitle(d) {
-      const issueKey = d.issueKey;
-      d.replacements = d.replacements || {};
-      d.replacements.default = { html: _t.html("inspector.unknown") };
-      return _t.html(`QA.improveOSM.error_types.${issueKey}.title`, d.replacements);
+    function gesture(that, args, clean2) {
+      return !clean2 && _activeGesture || new Gesture(that, args);
     }
-    function improveOsmHeader(selection2) {
-      const header = selection2.selectAll(".qa-header").data(
-        _qaItem ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      header.exit().remove();
-      const headerEnter = header.enter().append("div").attr("class", "qa-header");
-      const svgEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d) => d.id < 0).append("svg").attr("width", "20px").attr("height", "30px").attr("viewbox", "0 0 20 30").attr("class", (d) => `preset-icon-28 qaItem ${d.service} itemId-${d.id} itemType-${d.itemType}`);
-      svgEnter.append("polygon").attr("fill", "currentColor").attr("class", "qaItem-fill").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
-      svgEnter.append("use").attr("class", "icon-annotation").attr("width", "12px").attr("height", "12px").attr("transform", "translate(4, 5.5)").attr("xlink:href", (d) => d.icon ? "#" + d.icon : "");
-      headerEnter.append("div").attr("class", "qa-header-label").html(issueTitle);
+    function Gesture(that, args) {
+      this.that = that;
+      this.args = args;
+      this.active = 0;
+      this.extent = extent.apply(that, args);
     }
-    improveOsmHeader.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return improveOsmHeader;
+    Gesture.prototype = {
+      start: function(d3_event) {
+        if (++this.active === 1) {
+          _activeGesture = this;
+          dispatch14.call("start", this, d3_event);
+        }
+        return this;
+      },
+      zoom: function(d3_event, key, transform2) {
+        if (this.mouse && key !== "mouse") this.mouse[1] = transform2.invert(this.mouse[0]);
+        if (this.pointer0 && key !== "touch") this.pointer0[1] = transform2.invert(this.pointer0[0]);
+        if (this.pointer1 && key !== "touch") this.pointer1[1] = transform2.invert(this.pointer1[0]);
+        _transform = transform2;
+        dispatch14.call("zoom", this, d3_event, key, transform2);
+        return this;
+      },
+      end: function(d3_event) {
+        if (--this.active === 0) {
+          _activeGesture = null;
+          dispatch14.call("end", this, d3_event);
+        }
+        return this;
+      }
+    };
+    function wheeled(d3_event) {
+      if (!filter2.apply(this, arguments)) return;
+      var g3 = gesture(this, arguments), t2 = _transform, k2 = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t2.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p2 = utilFastMouse(this)(d3_event);
+      if (g3.wheel) {
+        if (g3.mouse[0][0] !== p2[0] || g3.mouse[0][1] !== p2[1]) {
+          g3.mouse[1] = t2.invert(g3.mouse[0] = p2);
+        }
+        clearTimeout(g3.wheel);
+      } else {
+        g3.mouse = [p2, t2.invert(p2)];
+        interrupt_default(this);
+        g3.start(d3_event);
+      }
+      d3_event.preventDefault();
+      d3_event.stopImmediatePropagation();
+      g3.wheel = setTimeout(wheelidled, _wheelDelay);
+      g3.zoom(d3_event, "mouse", constrain(translate(scale(t2, k2), g3.mouse[0], g3.mouse[1]), g3.extent, translateExtent));
+      function wheelidled() {
+        g3.wheel = null;
+        g3.end(d3_event);
+      }
+    }
+    var _downPointerIDs = /* @__PURE__ */ new Set();
+    var _pointerLocGetter;
+    function pointerdown(d3_event) {
+      _downPointerIDs.add(d3_event.pointerId);
+      if (!filter2.apply(this, arguments)) return;
+      var g3 = gesture(this, arguments, _downPointerIDs.size === 1);
+      var started;
+      d3_event.stopImmediatePropagation();
+      _pointerLocGetter = utilFastMouse(this);
+      var loc = _pointerLocGetter(d3_event);
+      var p2 = [loc, _transform.invert(loc), d3_event.pointerId];
+      if (!g3.pointer0) {
+        g3.pointer0 = p2;
+        started = true;
+      } else if (!g3.pointer1 && g3.pointer0[2] !== p2[2]) {
+        g3.pointer1 = p2;
+      }
+      if (started) {
+        interrupt_default(this);
+        g3.start(d3_event);
+      }
+    }
+    function pointermove(d3_event) {
+      if (!_downPointerIDs.has(d3_event.pointerId)) return;
+      if (!_activeGesture || !_pointerLocGetter) return;
+      var g3 = gesture(this, arguments);
+      var isPointer0 = g3.pointer0 && g3.pointer0[2] === d3_event.pointerId;
+      var isPointer1 = !isPointer0 && g3.pointer1 && g3.pointer1[2] === d3_event.pointerId;
+      if ((isPointer0 || isPointer1) && "buttons" in d3_event && !d3_event.buttons) {
+        if (g3.pointer0) _downPointerIDs.delete(g3.pointer0[2]);
+        if (g3.pointer1) _downPointerIDs.delete(g3.pointer1[2]);
+        g3.end(d3_event);
+        return;
+      }
+      d3_event.preventDefault();
+      d3_event.stopImmediatePropagation();
+      var loc = _pointerLocGetter(d3_event);
+      var t2, p2, l2;
+      if (isPointer0) g3.pointer0[0] = loc;
+      else if (isPointer1) g3.pointer1[0] = loc;
+      t2 = _transform;
+      if (g3.pointer1) {
+        var p02 = g3.pointer0[0], l0 = g3.pointer0[1], p1 = g3.pointer1[0], l1 = g3.pointer1[1], dp = (dp = p1[0] - p02[0]) * dp + (dp = p1[1] - p02[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
+        t2 = scale(t2, Math.sqrt(dp / dl));
+        p2 = [(p02[0] + p1[0]) / 2, (p02[1] + p1[1]) / 2];
+        l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
+      } else if (g3.pointer0) {
+        p2 = g3.pointer0[0];
+        l2 = g3.pointer0[1];
+      } else {
+        return;
+      }
+      g3.zoom(d3_event, "touch", constrain(translate(t2, p2, l2), g3.extent, translateExtent));
+    }
+    function pointerup(d3_event) {
+      if (!_downPointerIDs.has(d3_event.pointerId)) return;
+      _downPointerIDs.delete(d3_event.pointerId);
+      if (!_activeGesture) return;
+      var g3 = gesture(this, arguments);
+      d3_event.stopImmediatePropagation();
+      if (g3.pointer0 && g3.pointer0[2] === d3_event.pointerId) delete g3.pointer0;
+      else if (g3.pointer1 && g3.pointer1[2] === d3_event.pointerId) delete g3.pointer1;
+      if (g3.pointer1 && !g3.pointer0) {
+        g3.pointer0 = g3.pointer1;
+        delete g3.pointer1;
+      }
+      if (g3.pointer0) {
+        g3.pointer0[1] = _transform.invert(g3.pointer0[0]);
+      } else {
+        g3.end(d3_event);
+      }
+    }
+    zoom.wheelDelta = function(_2) {
+      return arguments.length ? (wheelDelta = utilFunctor(+_2), zoom) : wheelDelta;
+    };
+    zoom.filter = function(_2) {
+      return arguments.length ? (filter2 = utilFunctor(!!_2), zoom) : filter2;
+    };
+    zoom.extent = function(_2) {
+      return arguments.length ? (extent = utilFunctor([[+_2[0][0], +_2[0][1]], [+_2[1][0], +_2[1][1]]]), zoom) : extent;
     };
-    return improveOsmHeader;
+    zoom.scaleExtent = function(_2) {
+      return arguments.length ? (scaleExtent[0] = +_2[0], scaleExtent[1] = +_2[1], zoom) : [scaleExtent[0], scaleExtent[1]];
+    };
+    zoom.translateExtent = function(_2) {
+      return arguments.length ? (translateExtent[0][0] = +_2[0][0], translateExtent[1][0] = +_2[1][0], translateExtent[0][1] = +_2[0][1], translateExtent[1][1] = +_2[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
+    };
+    zoom.constrain = function(_2) {
+      return arguments.length ? (constrain = _2, zoom) : constrain;
+    };
+    zoom.interpolate = function(_2) {
+      return arguments.length ? (interpolate = _2, zoom) : interpolate;
+    };
+    zoom._transform = function(_2) {
+      return arguments.length ? (_transform = _2, zoom) : _transform;
+    };
+    return utilRebind(zoom, dispatch14, "on");
   }
 
-  // modules/ui/improveOSM_editor.js
-  function uiImproveOsmEditor(context) {
-    const dispatch10 = dispatch_default("change");
-    const qaDetails = uiImproveOsmDetails(context);
-    const qaComments = uiImproveOsmComments(context);
-    const qaHeader = uiImproveOsmHeader(context);
-    let _qaItem;
-    function improveOsmEditor(selection2) {
-      const headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("QA.improveOSM.title"));
-      let body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      const editor = body.selectAll(".qa-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(qaComments.issue(_qaItem)).call(improveOsmSaveSection);
+  // modules/util/double_up.js
+  function utilDoubleUp() {
+    var dispatch14 = dispatch_default("doubleUp");
+    var _maxTimespan = 500;
+    var _maxDistance = 20;
+    var _pointer;
+    function pointerIsValidFor(loc) {
+      return (/* @__PURE__ */ new Date()).getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
+      geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
     }
-    function improveOsmSaveSection(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      const isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
-      let saveSection = selection2.selectAll(".qa-save").data(
-        isShown ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      saveSection.exit().remove();
-      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
-      saveSectionEnter.append("h4").attr("class", ".qa-save-header").call(_t.append("note.newComment"));
-      saveSectionEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("QA.keepRight.comment_placeholder")).attr("maxlength", 1e3).property("value", (d) => d.newComment).call(utilNoAuto).on("input", changeInput).on("blur", changeInput);
-      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
-      function changeInput() {
-        const input = select_default2(this);
-        let val = input.property("value").trim();
-        if (val === "") {
-          val = void 0;
-        }
-        _qaItem = _qaItem.update({ newComment: val });
-        const qaService = services.improveOSM;
-        if (qaService) {
-          qaService.replaceItem(_qaItem);
-        }
-        saveSection.call(qaSaveButtons);
+    function pointerdown(d3_event) {
+      if (d3_event.ctrlKey || d3_event.button === 2) return;
+      var loc = [d3_event.clientX, d3_event.clientY];
+      if (_pointer && !pointerIsValidFor(loc)) {
+        _pointer = void 0;
+      }
+      if (!_pointer) {
+        _pointer = {
+          startLoc: loc,
+          startTime: (/* @__PURE__ */ new Date()).getTime(),
+          upCount: 0,
+          pointerId: d3_event.pointerId
+        };
+      } else {
+        _pointer.pointerId = d3_event.pointerId;
       }
     }
-    function qaSaveButtons(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d) => d.status + d.id);
-      buttonSection.exit().remove();
-      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("QA.keepRight.save_comment"));
-      buttonEnter.append("button").attr("class", "button close-button action");
-      buttonEnter.append("button").attr("class", "button ignore-button action");
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".comment-button").attr("disabled", (d) => d.newComment ? null : true).on("click.comment", function(d3_event, d) {
-        this.blur();
-        const qaService = services.improveOSM;
-        if (qaService) {
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
-        }
-      });
-      buttonSection.select(".close-button").html((d) => {
-        const andComment = d.newComment ? "_comment" : "";
-        return _t.html(`QA.keepRight.close${andComment}`);
-      }).on("click.close", function(d3_event, d) {
-        this.blur();
-        const qaService = services.improveOSM;
-        if (qaService) {
-          d.newStatus = "SOLVED";
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
-        }
-      });
-      buttonSection.select(".ignore-button").html((d) => {
-        const andComment = d.newComment ? "_comment" : "";
-        return _t.html(`QA.keepRight.ignore${andComment}`);
-      }).on("click.ignore", function(d3_event, d) {
-        this.blur();
-        const qaService = services.improveOSM;
-        if (qaService) {
-          d.newStatus = "INVALID";
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
+    function pointerup(d3_event) {
+      if (d3_event.ctrlKey || d3_event.button === 2) return;
+      if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
+      _pointer.upCount += 1;
+      if (_pointer.upCount === 2) {
+        var loc = [d3_event.clientX, d3_event.clientY];
+        if (pointerIsValidFor(loc)) {
+          var locInThis = utilFastMouse(this)(d3_event);
+          dispatch14.call("doubleUp", this, d3_event, locInThis);
         }
-      });
+        _pointer = void 0;
+      }
     }
-    improveOsmEditor.error = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return improveOsmEditor;
+    function doubleUp(selection2) {
+      if ("PointerEvent" in window) {
+        selection2.on("pointerdown.doubleUp", pointerdown).on("pointerup.doubleUp", pointerup);
+      } else {
+        selection2.on("dblclick.doubleUp", function(d3_event) {
+          dispatch14.call("doubleUp", this, d3_event, utilFastMouse(this)(d3_event));
+        });
+      }
+    }
+    doubleUp.off = function(selection2) {
+      selection2.on("pointerdown.doubleUp", null).on("pointerup.doubleUp", null).on("dblclick.doubleUp", null);
     };
-    return utilRebind(improveOsmEditor, dispatch10, "on");
+    return utilRebind(doubleUp, dispatch14, "on");
   }
 
-  // modules/ui/preset_list.js
-  function uiPresetList(context) {
-    var dispatch10 = dispatch_default("cancel", "choose");
-    var _entityIDs;
-    var _currLoc;
-    var _currentPresets;
-    var _autofocus = false;
-    function presetList(selection2) {
-      if (!_entityIDs)
-        return;
-      var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
-      selection2.html("");
-      var messagewrap = selection2.append("div").attr("class", "header fillL");
-      var message = messagewrap.append("h2").call(_t.append("inspector.choose"));
-      var direction = _mainLocalizer.textDirection() === "rtl" ? "backward" : "forward";
-      messagewrap.append("button").attr("class", "preset-choose").attr("title", direction).on("click", function() {
-        dispatch10.call("cancel", this);
-      }).call(svgIcon(`#iD-icon-${direction}`));
-      function initialKeydown(d3_event) {
-        if (search.property("value").length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          operationDelete(context, _entityIDs)();
-        } else if (search.property("value").length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
-          d3_event.preventDefault();
-          d3_event.stopPropagation();
-          context.undo();
-        } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
-          select_default2(this).on("keydown", keydown);
-          keydown.call(this, d3_event);
+  // modules/renderer/map.js
+  var TILESIZE = 256;
+  var minZoom2 = 2;
+  var maxZoom = 24;
+  var kMin = geoZoomToScale(minZoom2, TILESIZE);
+  var kMax = geoZoomToScale(maxZoom, TILESIZE);
+  function clamp2(num, min3, max3) {
+    return Math.max(min3, Math.min(num, max3));
+  }
+  function rendererMap(context) {
+    var dispatch14 = dispatch_default(
+      "move",
+      "drawn",
+      "crossEditableZoom",
+      "hitMinZoom",
+      "changeHighlighting",
+      "changeAreaFill"
+    );
+    var projection2 = context.projection;
+    var curtainProjection = context.curtainProjection;
+    var drawLayers;
+    var drawPoints;
+    var drawVertices;
+    var drawLines;
+    var drawAreas;
+    var drawMidpoints;
+    var drawLabels;
+    var _selection = select_default2(null);
+    var supersurface = select_default2(null);
+    var wrapper = select_default2(null);
+    var surface = select_default2(null);
+    var _dimensions = [1, 1];
+    var _dblClickZoomEnabled = true;
+    var _redrawEnabled = true;
+    var _gestureTransformStart;
+    var _transformStart = projection2.transform();
+    var _transformLast;
+    var _isTransformed = false;
+    var _minzoom = 0;
+    var _getMouseCoords;
+    var _lastPointerEvent;
+    var _lastWithinEditableZoom;
+    var _pointerDown = false;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    var _zoomerPannerFunction = "PointerEvent" in window ? utilZoomPan : zoom_default2;
+    var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(value_default).filter(zoomEventFilter).on("zoom.map", zoomPan2).on("start.map", function(d3_event) {
+      _pointerDown = d3_event && (d3_event.type === "pointerdown" || d3_event.sourceEvent && d3_event.sourceEvent.type === "pointerdown");
+    }).on("end.map", function() {
+      _pointerDown = false;
+    });
+    var _doubleUpHandler = utilDoubleUp();
+    var scheduleRedraw = throttle_default(redraw, 750);
+    function cancelPendingRedraw() {
+      scheduleRedraw.cancel();
+    }
+    function map2(selection2) {
+      _selection = selection2;
+      context.on("change.map", immediateRedraw);
+      var osm = context.connection();
+      if (osm) {
+        osm.on("change.map", immediateRedraw);
+      }
+      function didUndoOrRedo(targetTransform) {
+        var mode = context.mode().id;
+        if (mode !== "browse" && mode !== "select") return;
+        if (targetTransform) {
+          map2.transformEase(targetTransform);
         }
       }
-      function keydown(d3_event) {
-        if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"] && search.node().selectionStart === search.property("value").length) {
-          d3_event.preventDefault();
+      context.history().on("merge.map", function() {
+        scheduleRedraw();
+      }).on("change.map", immediateRedraw).on("undone.map", function(stack, fromStack) {
+        didUndoOrRedo(fromStack.transform);
+      }).on("redone.map", function(stack) {
+        didUndoOrRedo(stack.transform);
+      });
+      context.background().on("change.map", immediateRedraw);
+      context.features().on("redraw.map", immediateRedraw);
+      drawLayers.on("change.map", function() {
+        context.background().updateImagery();
+        immediateRedraw();
+      });
+      selection2.on("wheel.map mousewheel.map", function(d3_event) {
+        d3_event.preventDefault();
+      }).call(_zoomerPanner).call(_zoomerPanner.transform, projection2.transform()).on("dblclick.zoom", null);
+      map2.supersurface = supersurface = selection2.append("div").attr("class", "supersurface").call(utilSetTransform, 0, 0);
+      wrapper = supersurface.append("div").attr("class", "layer layer-data");
+      map2.surface = surface = wrapper.call(drawLayers).selectAll(".surface");
+      surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + "down.zoom", function(d3_event) {
+        _lastPointerEvent = d3_event;
+        if (d3_event.button === 2) {
           d3_event.stopPropagation();
-          var buttons = list.selectAll(".preset-list-button");
-          if (!buttons.empty())
-            buttons.nodes()[0].focus();
         }
-      }
-      function keypress(d3_event) {
-        var value = search.property("value");
-        if (d3_event.keyCode === 13 && value.length) {
-          list.selectAll(".preset-list-item:first-child").each(function(d) {
-            d.choose.call(this);
-          });
+      }, true).on(_pointerPrefix + "up.zoom", function(d3_event) {
+        _lastPointerEvent = d3_event;
+        if (resetTransform()) {
+          immediateRedraw();
         }
-      }
-      function inputevent() {
-        var value = search.property("value");
-        list.classed("filtered", value.length);
-        var results, messageText;
-        if (value.length) {
-          results = presets.search(value, entityGeometries()[0], _currLoc);
-          messageText = _t.html("inspector.results", {
-            n: results.collection.length,
-            search: value
-          });
-        } else {
-          var entityPresets2 = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
-          results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets2);
-          messageText = _t.html("inspector.choose");
+      }).on(_pointerPrefix + "move.map", function(d3_event) {
+        _lastPointerEvent = d3_event;
+      }).on(_pointerPrefix + "over.vertices", function(d3_event) {
+        if (map2.editableDataEnabled() && !_isTransformed) {
+          var hover = d3_event.target.__data__;
+          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
+          dispatch14.call("drawn", this, { full: false });
         }
-        list.call(drawList, results);
-        message.html(messageText);
-      }
-      var searchWrap = selection2.append("div").attr("class", "search-header");
-      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
-      var search = searchWrap.append("input").attr("class", "preset-search-input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keydown", initialKeydown).on("keypress", keypress).on("input", debounce_default(inputevent));
-      if (_autofocus) {
-        search.node().focus();
-        setTimeout(function() {
-          search.node().focus();
-        }, 0);
+      }).on(_pointerPrefix + "out.vertices", function(d3_event) {
+        if (map2.editableDataEnabled() && !_isTransformed) {
+          var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
+          surface.call(drawVertices.drawHover, context.graph(), hover, map2.extent());
+          dispatch14.call("drawn", this, { full: false });
+        }
+      });
+      var detected = utilDetect();
+      if ("GestureEvent" in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
+      // but we only need to do this on desktop Safari anyway. – #7694
+      !detected.isMobileWebKit) {
+        surface.on("gesturestart.surface", function(d3_event) {
+          d3_event.preventDefault();
+          _gestureTransformStart = projection2.transform();
+        }).on("gesturechange.surface", gestureChange);
       }
-      var listWrap = selection2.append("div").attr("class", "inspector-body");
-      var entityPresets = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
-      var list = listWrap.append("div").attr("class", "preset-list").call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets));
-      context.features().on("change.preset-list", updateForFeatureHiddenState);
-    }
-    function drawList(list, presets) {
-      presets = presets.matchAllGeometry(entityGeometries());
-      var collection = presets.collection.reduce(function(collection2, preset) {
-        if (!preset)
-          return collection2;
-        if (preset.members) {
-          if (preset.members.collection.filter(function(preset2) {
-            return preset2.addable();
-          }).length > 1) {
-            collection2.push(CategoryItem(preset));
+      updateAreaFill();
+      _doubleUpHandler.on("doubleUp.map", function(d3_event, p02) {
+        if (!_dblClickZoomEnabled) return;
+        if (typeof d3_event.target.__data__ === "object" && // or area fills
+        !select_default2(d3_event.target).classed("fill")) return;
+        var zoomOut2 = d3_event.shiftKey;
+        var t2 = projection2.transform();
+        var p1 = t2.invert(p02);
+        t2 = t2.scale(zoomOut2 ? 0.5 : 2);
+        t2.x = p02[0] - p1[0] * t2.k;
+        t2.y = p02[1] - p1[1] * t2.k;
+        map2.transformEase(t2);
+      });
+      context.on("enter.map", function() {
+        if (!map2.editableDataEnabled(
+          true
+          /* skip zoom check */
+        )) return;
+        if (_isTransformed) return;
+        var graph = context.graph();
+        var selectedAndParents = {};
+        context.selectedIDs().forEach(function(id2) {
+          var entity = graph.hasEntity(id2);
+          if (entity) {
+            selectedAndParents[entity.id] = entity;
+            if (entity.type === "node") {
+              graph.parentWays(entity).forEach(function(parent) {
+                selectedAndParents[parent.id] = parent;
+              });
+            }
           }
-        } else if (preset.addable()) {
-          collection2.push(PresetItem(preset));
-        }
-        return collection2;
-      }, []);
-      var items = list.selectAll(".preset-list-item").data(collection, function(d) {
-        return d.preset.id;
+        });
+        var data = Object.values(selectedAndParents);
+        var filter2 = function(d2) {
+          return d2.id in selectedAndParents;
+        };
+        data = context.features().filter(data, graph);
+        surface.call(drawVertices.drawSelected, graph, map2.extent()).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent());
+        dispatch14.call("drawn", this, { full: false });
+        scheduleRedraw();
       });
-      items.order();
-      items.exit().remove();
-      items.enter().append("div").attr("class", function(item) {
-        return "preset-list-item preset-" + item.preset.id.replace("/", "-");
-      }).classed("current", function(item) {
-        return _currentPresets.indexOf(item.preset) !== -1;
-      }).each(function(item) {
-        select_default2(this).call(item);
-      }).style("opacity", 0).transition().style("opacity", 1);
-      updateForFeatureHiddenState();
+      map2.dimensions(utilGetDimensions(selection2));
     }
-    function itemKeydown(d3_event) {
-      var item = select_default2(this.closest(".preset-list-item"));
-      var parentItem = select_default2(item.node().parentNode.closest(".preset-list-item"));
-      if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"]) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        var nextItem = select_default2(item.node().nextElementSibling);
-        if (nextItem.empty()) {
-          if (!parentItem.empty()) {
-            nextItem = select_default2(parentItem.node().nextElementSibling);
+    function zoomEventFilter(d3_event) {
+      if (d3_event.type === "mousedown") {
+        var hasOrphan = false;
+        var listeners = window.__on;
+        for (var i3 = 0; i3 < listeners.length; i3++) {
+          var listener = listeners[i3];
+          if (listener.name === "zoom" && listener.type === "mouseup") {
+            hasOrphan = true;
+            break;
           }
-        } else if (select_default2(this).classed("expanded")) {
-          nextItem = item.select(".subgrid .preset-list-item:first-child");
-        }
-        if (!nextItem.empty()) {
-          nextItem.select(".preset-list-button").node().focus();
         }
-      } else if (d3_event.keyCode === utilKeybinding.keyCodes["\u2191"]) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        var previousItem = select_default2(item.node().previousElementSibling);
-        if (previousItem.empty()) {
-          if (!parentItem.empty()) {
-            previousItem = parentItem;
+        if (hasOrphan) {
+          var event = window.CustomEvent;
+          if (event) {
+            event = new event("mouseup");
+          } else {
+            event = window.document.createEvent("Event");
+            event.initEvent("mouseup", false, false);
           }
-        } else if (previousItem.select(".preset-list-button").classed("expanded")) {
-          previousItem = previousItem.select(".subgrid .preset-list-item:last-child");
-        }
-        if (!previousItem.empty()) {
-          previousItem.select(".preset-list-button").node().focus();
-        } else {
-          var search = select_default2(this.closest(".preset-list-pane")).select(".preset-search-input");
-          search.node().focus();
-        }
-      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        if (!parentItem.empty()) {
-          parentItem.select(".preset-list-button").node().focus();
+          event.view = window;
+          window.dispatchEvent(event);
         }
-      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        item.datum().choose.call(select_default2(this).node());
       }
+      return d3_event.button !== 2;
     }
-    function CategoryItem(preset) {
-      var box, sublist, shown = false;
-      function item(selection2) {
-        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap category");
-        function click() {
-          var isExpanded = select_default2(this).classed("expanded");
-          var iconName = isExpanded ? _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward" : "#iD-icon-down";
-          select_default2(this).classed("expanded", !isExpanded).attr("title", !isExpanded ? _t("icons.collapse") : _t("icons.expand"));
-          select_default2(this).selectAll("div.label-inner svg.icon use").attr("href", iconName);
-          item.choose();
-        }
-        var geometries = entityGeometries();
-        var button = wrap2.append("button").attr("class", "preset-list-button").attr("title", _t("icons.expand")).classed("expanded", false).call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", click).on("keydown", function(d3_event) {
-          if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            if (!select_default2(this).classed("expanded")) {
-              click.call(this, d3_event);
-            }
-          } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
-            d3_event.preventDefault();
-            d3_event.stopPropagation();
-            if (select_default2(this).classed("expanded")) {
-              click.call(this, d3_event);
-            }
-          } else {
-            itemKeydown.call(this, d3_event);
-          }
+    function pxCenter() {
+      return [_dimensions[0] / 2, _dimensions[1] / 2];
+    }
+    function drawEditable(difference2, extent) {
+      var mode = context.mode();
+      var graph = context.graph();
+      var features = context.features();
+      var all = context.history().intersects(map2.extent());
+      var fullRedraw = false;
+      var data;
+      var set4;
+      var filter2;
+      var applyFeatureLayerFilters = true;
+      if (map2.isInWideSelection()) {
+        data = [];
+        utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function(id2) {
+          var entity = context.hasEntity(id2);
+          if (entity) data.push(entity);
         });
-        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
-        label.append("div").attr("class", "namepart").call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward", "inline")).append("span").call(preset.nameLabel()).append("span").text("\u2026");
-        box = selection2.append("div").attr("class", "subgrid").style("max-height", "0px").style("opacity", 0);
-        box.append("div").attr("class", "arrow");
-        sublist = box.append("div").attr("class", "preset-list fillL3");
-      }
-      item.choose = function() {
-        if (!box || !sublist)
-          return;
-        if (shown) {
-          shown = false;
-          box.transition().duration(200).style("opacity", "0").style("max-height", "0px").style("padding-bottom", "0px");
+        fullRedraw = true;
+        filter2 = utilFunctor(true);
+        applyFeatureLayerFilters = false;
+      } else if (difference2) {
+        var complete = difference2.complete(map2.extent());
+        data = Object.values(complete).filter(Boolean);
+        set4 = new Set(Object.keys(complete));
+        filter2 = function(d2) {
+          return set4.has(d2.id);
+        };
+        features.clear(data);
+      } else {
+        if (features.gatherStats(all, graph, _dimensions)) {
+          extent = void 0;
+        }
+        if (extent) {
+          data = context.history().intersects(map2.extent().intersection(extent));
+          set4 = new Set(data.map(function(entity) {
+            return entity.id;
+          }));
+          filter2 = function(d2) {
+            return set4.has(d2.id);
+          };
         } else {
-          shown = true;
-          var members = preset.members.matchAllGeometry(entityGeometries());
-          sublist.call(drawList, members);
-          box.transition().duration(200).style("opacity", "1").style("max-height", 200 + members.collection.length * 190 + "px").style("padding-bottom", "10px");
+          data = all;
+          fullRedraw = true;
+          filter2 = utilFunctor(true);
         }
-      };
-      item.preset = preset;
-      return item;
+      }
+      if (applyFeatureLayerFilters) {
+        data = features.filter(data, graph);
+      } else {
+        context.features().resetStats();
+      }
+      if (mode && mode.id === "select") {
+        surface.call(drawVertices.drawSelected, graph, map2.extent());
+      }
+      surface.call(drawVertices, graph, data, filter2, map2.extent(), fullRedraw).call(drawLines, graph, data, filter2).call(drawAreas, graph, data, filter2).call(drawMidpoints, graph, data, filter2, map2.trimmedExtent()).call(drawLabels, graph, data, filter2, _dimensions, fullRedraw).call(drawPoints, graph, data, filter2);
+      dispatch14.call("drawn", this, { full: true });
     }
-    function PresetItem(preset) {
-      function item(selection2) {
-        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap");
-        var geometries = entityGeometries();
-        var button = wrap2.append("button").attr("class", "preset-list-button").call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", item.choose).on("keydown", itemKeydown);
-        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
-        var nameparts = [
-          preset.nameLabel(),
-          preset.subtitleLabel()
-        ].filter(Boolean);
-        label.selectAll(".namepart").data(nameparts, (d) => d.stringId).enter().append("div").attr("class", "namepart").text("").each(function(d) {
-          d(select_default2(this));
-        });
-        wrap2.call(item.reference.button);
-        selection2.call(item.reference.body);
-      }
-      item.choose = function() {
-        if (select_default2(this).classed("disabled"))
-          return;
-        if (!context.inIntro()) {
-          _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
-        }
-        context.perform(
-          function(graph) {
-            for (var i2 in _entityIDs) {
-              var entityID = _entityIDs[i2];
-              var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
-              graph = actionChangePreset(entityID, oldPreset, preset)(graph);
-            }
-            return graph;
-          },
-          _t("operations.change_tags.annotation")
-        );
-        context.validator().validate();
-        dispatch10.call("choose", this, preset);
+    map2.init = function() {
+      drawLayers = svgLayers(projection2, context);
+      drawPoints = svgPoints(projection2, context);
+      drawVertices = svgVertices(projection2, context);
+      drawLines = svgLines(projection2, context);
+      drawAreas = svgAreas(projection2, context);
+      drawMidpoints = svgMidpoints(projection2, context);
+      drawLabels = svgLabels(projection2, context);
+    };
+    function editOff() {
+      context.features().resetStats();
+      surface.selectAll(".layer-osm *").remove();
+      surface.selectAll(".layer-touch:not(.markers) *").remove();
+      var allowed = {
+        "browse": true,
+        "save": true,
+        "select-note": true,
+        "select-data": true,
+        "select-error": true
       };
-      item.help = function(d3_event) {
-        d3_event.stopPropagation();
-        item.reference.toggle();
+      var mode = context.mode();
+      if (mode && !allowed[mode.id]) {
+        context.enter(modeBrowse(context));
+      }
+      dispatch14.call("drawn", this, { full: true });
+    }
+    function gestureChange(d3_event) {
+      var e3 = d3_event;
+      e3.preventDefault();
+      var props = {
+        deltaMode: 0,
+        // dummy values to ignore in zoomPan
+        deltaY: 1,
+        // dummy values to ignore in zoomPan
+        clientX: e3.clientX,
+        clientY: e3.clientY,
+        screenX: e3.screenX,
+        screenY: e3.screenY,
+        x: e3.x,
+        y: e3.y
       };
-      item.preset = preset;
-      item.reference = uiTagReference(preset.reference(), context);
-      return item;
+      var e22 = new WheelEvent("wheel", props);
+      e22._scale = e3.scale;
+      e22._rotation = e3.rotation;
+      _selection.node().dispatchEvent(e22);
     }
-    function updateForFeatureHiddenState() {
-      if (!_entityIDs.every(context.hasEntity))
-        return;
-      var geometries = entityGeometries();
-      var button = context.container().selectAll(".preset-list .preset-list-button");
-      button.call(uiTooltip().destroyAny);
-      button.each(function(item, index) {
-        var hiddenPresetFeaturesId;
-        for (var i2 in geometries) {
-          hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i2]);
-          if (hiddenPresetFeaturesId)
-            break;
-        }
-        var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
-        select_default2(this).classed("disabled", isHiddenPreset);
-        if (isHiddenPreset) {
-          var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
-          select_default2(this).call(
-            uiTooltip().title(() => _t.append("inspector.hidden_preset." + (isAutoHidden ? "zoom" : "manual"), {
-              features: _t("feature." + hiddenPresetFeaturesId + ".description")
-            })).placement(index < 2 ? "bottom" : "top")
+    function zoomPan2(event, key, transform2) {
+      var source = event && event.sourceEvent || event;
+      var eventTransform = transform2 || event && event.transform;
+      var x2 = eventTransform.x;
+      var y2 = eventTransform.y;
+      var k2 = eventTransform.k;
+      if (source && source.type === "wheel") {
+        if (_pointerDown) return;
+        var detected = utilDetect();
+        var dX = source.deltaX;
+        var dY = source.deltaY;
+        var x22 = x2;
+        var y22 = y2;
+        var k22 = k2;
+        var t0, p02, p1;
+        if (source.deltaMode === 1) {
+          var lines = Math.abs(source.deltaY);
+          var sign2 = source.deltaY > 0 ? 1 : -1;
+          dY = sign2 * clamp2(
+            Math.exp((lines - 1) * 0.75) * 4.000244140625,
+            4.000244140625,
+            // min
+            350.000244140625
+            // max
           );
+          if (detected.os !== "mac") {
+            dY *= 5;
+          }
+          t0 = _isTransformed ? _transformLast : _transformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * Math.pow(2, -dY / 500);
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if (source._scale) {
+          t0 = _gestureTransformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * source._scale;
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if (source.ctrlKey && !isInteger(dY)) {
+          dY *= 6;
+          t0 = _isTransformed ? _transformLast : _transformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * Math.pow(2, -dY / 500);
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
+          t0 = _isTransformed ? _transformLast : _transformStart;
+          p02 = _getMouseCoords(source);
+          p1 = t0.invert(p02);
+          k22 = t0.k * Math.pow(2, -dY / 500);
+          k22 = clamp2(k22, kMin, kMax);
+          x22 = p02[0] - p1[0] * k22;
+          y22 = p02[1] - p1[1] * k22;
+        } else if (detected.os === "mac" && detected.browser !== "Firefox" && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
+          p1 = projection2.translate();
+          x22 = p1[0] - dX;
+          y22 = p1[1] - dY;
+          k22 = projection2.scale();
+          k22 = clamp2(k22, kMin, kMax);
+        }
+        if (x22 !== x2 || y22 !== y2 || k22 !== k2) {
+          x2 = x22;
+          y2 = y22;
+          k2 = k22;
+          eventTransform = identity2.translate(x22, y22).scale(k22);
+          if (_zoomerPanner._transform) {
+            _zoomerPanner._transform(eventTransform);
+          } else {
+            _selection.node().__zoom = eventTransform;
+          }
         }
-      });
-    }
-    presetList.autofocus = function(val) {
-      if (!arguments.length)
-        return _autofocus;
-      _autofocus = val;
-      return presetList;
-    };
-    presetList.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      _currLoc = null;
-      if (_entityIDs && _entityIDs.length) {
-        const extent = _entityIDs.reduce(function(extent2, entityID) {
-          var entity = context.graph().entity(entityID);
-          return extent2.extend(entity.extent(context.graph()));
-        }, geoExtent());
-        _currLoc = extent.center();
-        var presets = _entityIDs.map(function(entityID) {
-          return _mainPresetIndex.match(context.entity(entityID), context.graph());
-        });
-        presetList.presets(presets);
       }
-      return presetList;
-    };
-    presetList.presets = function(val) {
-      if (!arguments.length)
-        return _currentPresets;
-      _currentPresets = val;
-      return presetList;
-    };
-    function entityGeometries() {
-      var counts = {};
-      for (var i2 in _entityIDs) {
-        var entityID = _entityIDs[i2];
-        var entity = context.entity(entityID);
-        var geometry = entity.geometry(context.graph());
-        if (geometry === "vertex" && entity.isOnAddressLine(context.graph())) {
-          geometry = "point";
+      if (_transformStart.x === x2 && _transformStart.y === y2 && _transformStart.k === k2) {
+        return;
+      }
+      if (geoScaleToZoom(k2, TILESIZE) < _minzoom) {
+        surface.interrupt();
+        dispatch14.call("hitMinZoom", this, map2);
+        setCenterZoom(map2.center(), context.minEditableZoom(), 0, true);
+        scheduleRedraw();
+        dispatch14.call("move", this, map2);
+        return;
+      }
+      projection2.transform(eventTransform);
+      var withinEditableZoom = map2.withinEditableZoom();
+      if (_lastWithinEditableZoom !== withinEditableZoom) {
+        if (_lastWithinEditableZoom !== void 0) {
+          dispatch14.call("crossEditableZoom", this, withinEditableZoom);
         }
-        if (!counts[geometry])
-          counts[geometry] = 0;
-        counts[geometry] += 1;
+        _lastWithinEditableZoom = withinEditableZoom;
+      }
+      var scale = k2 / _transformStart.k;
+      var tX = (x2 / scale - _transformStart.x) * scale;
+      var tY = (y2 / scale - _transformStart.y) * scale;
+      if (context.inIntro()) {
+        curtainProjection.transform({
+          x: x2 - tX,
+          y: y2 - tY,
+          k: k2
+        });
+      }
+      if (source) {
+        _lastPointerEvent = event;
+      }
+      _isTransformed = true;
+      _transformLast = eventTransform;
+      utilSetTransform(supersurface, tX, tY, scale);
+      scheduleRedraw();
+      dispatch14.call("move", this, map2);
+      function isInteger(val) {
+        return typeof val === "number" && isFinite(val) && Math.floor(val) === val;
       }
-      return Object.keys(counts).sort(function(geom1, geom2) {
-        return counts[geom2] - counts[geom1];
-      });
     }
-    return utilRebind(presetList, dispatch10, "on");
-  }
-
-  // modules/ui/view_on_osm.js
-  function uiViewOnOSM(context) {
-    var _what;
-    function viewOnOSM(selection2) {
-      var url;
-      if (_what instanceof osmEntity) {
-        url = context.connection().entityURL(_what);
-      } else if (_what instanceof osmNote) {
-        url = context.connection().noteURL(_what);
+    function resetTransform() {
+      if (!_isTransformed) return false;
+      utilSetTransform(supersurface, 0, 0);
+      _isTransformed = false;
+      if (context.inIntro()) {
+        curtainProjection.transform(projection2.transform());
       }
-      var data = !_what || _what.isNew() ? [] : [_what];
-      var link2 = selection2.selectAll(".view-on-osm").data(data, function(d) {
-        return d.id;
-      });
-      link2.exit().remove();
-      var linkEnter = link2.enter().append("a").attr("class", "view-on-osm").attr("target", "_blank").attr("href", url).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("inspector.view_on_osm"));
+      return true;
     }
-    viewOnOSM.what = function(_) {
-      if (!arguments.length)
-        return _what;
-      _what = _;
-      return viewOnOSM;
-    };
-    return viewOnOSM;
-  }
-
-  // modules/ui/inspector.js
-  function uiInspector(context) {
-    var presetList = uiPresetList(context);
-    var entityEditor = uiEntityEditor(context);
-    var wrap2 = select_default2(null), presetPane = select_default2(null), editorPane = select_default2(null);
-    var _state = "select";
-    var _entityIDs;
-    var _newFeature = false;
-    function inspector(selection2) {
-      presetList.entityIDs(_entityIDs).autofocus(_newFeature).on("choose", inspector.setPreset).on("cancel", function() {
-        inspector.setPreset();
-      });
-      entityEditor.state(_state).entityIDs(_entityIDs).on("choose", inspector.showList);
-      wrap2 = selection2.selectAll(".panewrap").data([0]);
-      var enter = wrap2.enter().append("div").attr("class", "panewrap");
-      enter.append("div").attr("class", "preset-list-pane pane");
-      enter.append("div").attr("class", "entity-editor-pane pane");
-      wrap2 = wrap2.merge(enter);
-      presetPane = wrap2.selectAll(".preset-list-pane");
-      editorPane = wrap2.selectAll(".entity-editor-pane");
-      function shouldDefaultToPresetList() {
-        if (_state !== "select")
-          return false;
-        if (_entityIDs.length !== 1)
-          return false;
-        var entityID = _entityIDs[0];
-        var entity = context.hasEntity(entityID);
-        if (!entity)
-          return false;
-        if (entity.hasNonGeometryTags())
-          return false;
-        if (_newFeature)
-          return true;
-        if (entity.geometry(context.graph()) !== "vertex")
-          return false;
-        if (context.graph().parentRelations(entity).length)
-          return false;
-        if (context.validator().getEntityIssues(entityID).length)
-          return false;
-        if (entity.isHighwayIntersection(context.graph()))
-          return false;
-        return true;
+    function redraw(difference2, extent) {
+      if (surface.empty() || !_redrawEnabled) return;
+      if (resetTransform()) {
+        difference2 = extent = void 0;
       }
-      if (shouldDefaultToPresetList()) {
-        wrap2.style("right", "-100%");
-        editorPane.classed("hide", true);
-        presetPane.classed("hide", false).call(presetList);
+      var zoom = map2.zoom();
+      var z2 = String(~~zoom);
+      if (surface.attr("data-zoom") !== z2) {
+        surface.attr("data-zoom", z2);
+      }
+      var lat = map2.center()[1];
+      var lowzoom = linear3().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
+      surface.classed("low-zoom", zoom <= lowzoom(lat));
+      if (!difference2) {
+        supersurface.call(context.background());
+        wrapper.call(drawLayers);
+      }
+      if (map2.editableDataEnabled() || map2.isInWideSelection()) {
+        context.loadTiles(projection2);
+        drawEditable(difference2, extent);
       } else {
-        wrap2.style("right", "0%");
-        presetPane.classed("hide", true);
-        editorPane.classed("hide", false).call(entityEditor);
+        editOff();
       }
-      var footer = selection2.selectAll(".footer").data([0]);
-      footer = footer.enter().append("div").attr("class", "footer").merge(footer);
-      footer.call(
-        uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0]))
-      );
+      _transformStart = projection2.transform();
+      return map2;
     }
-    inspector.showList = function(presets) {
-      presetPane.classed("hide", false);
-      wrap2.transition().styleTween("right", function() {
-        return value_default("0%", "-100%");
-      }).on("end", function() {
-        editorPane.classed("hide", true);
-      });
-      if (presets) {
-        presetList.presets(presets);
-      }
-      presetPane.call(presetList.autofocus(true));
+    var immediateRedraw = function(difference2, extent) {
+      if (!difference2 && !extent) cancelPendingRedraw();
+      redraw(difference2, extent);
     };
-    inspector.setPreset = function(preset) {
-      if (preset && preset.id === "type/multipolygon") {
-        presetPane.call(presetList.autofocus(true));
-      } else {
-        editorPane.classed("hide", false);
-        wrap2.transition().styleTween("right", function() {
-          return value_default("-100%", "0%");
-        }).on("end", function() {
-          presetPane.classed("hide", true);
-        });
-        if (preset) {
-          entityEditor.presets([preset]);
+    map2.lastPointerEvent = function() {
+      return _lastPointerEvent;
+    };
+    map2.mouse = function(d3_event) {
+      var event = d3_event || _lastPointerEvent;
+      if (event) {
+        var s2;
+        while (s2 = event.sourceEvent) {
+          event = s2;
         }
-        editorPane.call(entityEditor);
+        return _getMouseCoords(event);
       }
+      return null;
     };
-    inspector.state = function(val) {
-      if (!arguments.length)
-        return _state;
-      _state = val;
-      entityEditor.state(_state);
-      context.container().selectAll(".field-help-body").remove();
-      return inspector;
+    map2.mouseCoordinates = function() {
+      var coord2 = map2.mouse() || pxCenter();
+      return projection2.invert(coord2);
     };
-    inspector.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
-      _entityIDs = val;
-      return inspector;
+    map2.dblclickZoomEnable = function(val) {
+      if (!arguments.length) return _dblClickZoomEnabled;
+      _dblClickZoomEnabled = val;
+      return map2;
     };
-    inspector.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
-      _newFeature = val;
-      return inspector;
+    map2.redrawEnable = function(val) {
+      if (!arguments.length) return _redrawEnabled;
+      _redrawEnabled = val;
+      return map2;
     };
-    return inspector;
-  }
-
-  // modules/ui/keepRight_details.js
-  function uiKeepRightDetails(context) {
-    let _qaItem;
-    function issueDetail(d) {
-      const { itemType, parentIssueType } = d;
-      const unknown = { html: _t.html("inspector.unknown") };
-      let replacements = d.replacements || {};
-      replacements.default = unknown;
-      if (_mainLocalizer.hasTextForStringId(`QA.keepRight.errorTypes.${itemType}.title`)) {
-        return _t.html(`QA.keepRight.errorTypes.${itemType}.description`, replacements);
+    map2.isTransformed = function() {
+      return _isTransformed;
+    };
+    function setTransform(t2, duration, force) {
+      var t3 = projection2.transform();
+      if (!force && t2.k === t3.k && t2.x === t3.x && t2.y === t3.y) return false;
+      if (duration) {
+        _selection.transition().duration(duration).on("start", function() {
+          map2.startEase();
+        }).call(_zoomerPanner.transform, identity2.translate(t2.x, t2.y).scale(t2.k));
       } else {
-        return _t.html(`QA.keepRight.errorTypes.${parentIssueType}.description`, replacements);
+        projection2.transform(t2);
+        _transformStart = t2;
+        _selection.call(_zoomerPanner.transform, _transformStart);
       }
+      return true;
     }
-    function keepRightDetails(selection2) {
-      const details = selection2.selectAll(".error-details").data(
-        _qaItem ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      details.exit().remove();
-      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
-      const descriptionEnter = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      descriptionEnter.append("h4").call(_t.append("QA.keepRight.detail_description"));
-      descriptionEnter.append("div").attr("class", "qa-details-description-text").html(issueDetail);
-      let relatedEntities = [];
-      descriptionEnter.selectAll(".error_entity_link, .error_object_link").attr("href", "#").each(function() {
-        const link2 = select_default2(this);
-        const isObjectLink = link2.classed("error_object_link");
-        const entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
-        const entity = context.hasEntity(entityID);
-        relatedEntities.push(entityID);
-        link2.on("mouseenter", () => {
-          utilHighlightEntities([entityID], true, context);
-        }).on("mouseleave", () => {
-          utilHighlightEntities([entityID], false, context);
-        }).on("click", (d3_event) => {
-          d3_event.preventDefault();
-          utilHighlightEntities([entityID], false, context);
-          const osmlayer = context.layers().layer("osm");
-          if (!osmlayer.enabled()) {
-            osmlayer.enabled(true);
-          }
-          context.map().centerZoomEase(_qaItem.loc, 20);
-          if (entity) {
-            context.enter(modeSelect(context, [entityID]));
-          } else {
-            context.loadEntity(entityID, (err, result) => {
-              if (err)
-                return;
-              const entity2 = result.data.find((e) => e.id === entityID);
-              if (entity2)
-                context.enter(modeSelect(context, [entityID]));
-            });
-          }
-        });
-        if (entity) {
-          let name = utilDisplayName(entity);
-          if (!name && !isObjectLink) {
-            const preset = _mainPresetIndex.match(entity, context.graph());
-            name = preset && !preset.isFallback() && preset.name();
-          }
-          if (name) {
-            this.innerText = name;
-          }
-        }
-      });
-      context.features().forceVisible(relatedEntities);
-      context.map().pan([0, 0]);
+    function setCenterZoom(loc2, z2, duration, force) {
+      var c2 = map2.center();
+      var z3 = map2.zoom();
+      if (loc2[0] === c2[0] && loc2[1] === c2[1] && z2 === z3 && !force) return false;
+      var proj = geoRawMercator().transform(projection2.transform());
+      var k2 = clamp2(geoZoomToScale(z2, TILESIZE), kMin, kMax);
+      proj.scale(k2);
+      var t2 = proj.translate();
+      var point = proj(loc2);
+      var center = pxCenter();
+      t2[0] += center[0] - point[0];
+      t2[1] += center[1] - point[1];
+      return setTransform(identity2.translate(t2[0], t2[1]).scale(k2), duration, force);
     }
-    keepRightDetails.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return keepRightDetails;
-    };
-    return keepRightDetails;
-  }
-
-  // modules/ui/keepRight_header.js
-  function uiKeepRightHeader() {
-    let _qaItem;
-    function issueTitle(d) {
-      const { itemType, parentIssueType } = d;
-      const unknown = _t.html("inspector.unknown");
-      let replacements = d.replacements || {};
-      replacements.default = { html: unknown };
-      if (_mainLocalizer.hasTextForStringId(`QA.keepRight.errorTypes.${itemType}.title`)) {
-        return _t.html(`QA.keepRight.errorTypes.${itemType}.title`, replacements);
+    map2.pan = function(delta, duration) {
+      var t2 = projection2.translate();
+      var k2 = projection2.scale();
+      t2[0] += delta[0];
+      t2[1] += delta[1];
+      if (duration) {
+        _selection.transition().duration(duration).on("start", function() {
+          map2.startEase();
+        }).call(_zoomerPanner.transform, identity2.translate(t2[0], t2[1]).scale(k2));
       } else {
-        return _t.html(`QA.keepRight.errorTypes.${parentIssueType}.title`, replacements);
+        projection2.translate(t2);
+        _transformStart = projection2.transform();
+        _selection.call(_zoomerPanner.transform, _transformStart);
+        dispatch14.call("move", this, map2);
+        immediateRedraw();
       }
+      return map2;
+    };
+    map2.dimensions = function(val) {
+      if (!arguments.length) return _dimensions;
+      _dimensions = val;
+      drawLayers.dimensions(_dimensions);
+      context.background().dimensions(_dimensions);
+      projection2.clipExtent([[0, 0], _dimensions]);
+      _getMouseCoords = utilFastMouse(supersurface.node());
+      scheduleRedraw();
+      return map2;
+    };
+    function zoomIn(delta) {
+      setCenterZoom(map2.center(), ~~map2.zoom() + delta, 250, true);
     }
-    function keepRightHeader(selection2) {
-      const header = selection2.selectAll(".qa-header").data(
-        _qaItem ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      header.exit().remove();
-      const headerEnter = header.enter().append("div").attr("class", "qa-header");
-      const iconEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d) => d.id < 0);
-      iconEnter.append("div").attr("class", (d) => `preset-icon-28 qaItem ${d.service} itemId-${d.id} itemType-${d.parentIssueType}`).call(svgIcon("#iD-icon-bolt", "qaItem-fill"));
-      headerEnter.append("div").attr("class", "qa-header-label").html(issueTitle);
+    function zoomOut(delta) {
+      setCenterZoom(map2.center(), ~~map2.zoom() - delta, 250, true);
     }
-    keepRightHeader.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return keepRightHeader;
+    map2.zoomIn = function() {
+      zoomIn(1);
     };
-    return keepRightHeader;
-  }
-
-  // modules/ui/view_on_keepRight.js
-  function uiViewOnKeepRight() {
-    let _qaItem;
-    function viewOnKeepRight(selection2) {
-      let url;
-      if (services.keepRight && _qaItem instanceof QAItem) {
-        url = services.keepRight.issueURL(_qaItem);
-      }
-      const link2 = selection2.selectAll(".view-on-keepRight").data(url ? [url] : []);
-      link2.exit().remove();
-      const linkEnter = link2.enter().append("a").attr("class", "view-on-keepRight").attr("target", "_blank").attr("rel", "noopener").attr("href", (d) => d).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("inspector.view_on_keepRight"));
-    }
-    viewOnKeepRight.what = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return viewOnKeepRight;
+    map2.zoomInFurther = function() {
+      zoomIn(4);
     };
-    return viewOnKeepRight;
-  }
-
-  // modules/ui/keepRight_editor.js
-  function uiKeepRightEditor(context) {
-    const dispatch10 = dispatch_default("change");
-    const qaDetails = uiKeepRightDetails(context);
-    const qaHeader = uiKeepRightHeader(context);
-    let _qaItem;
-    function keepRightEditor(selection2) {
-      const headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("QA.keepRight.title"));
-      let body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      const editor = body.selectAll(".qa-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
-      const footer = selection2.selectAll(".footer").data([0]);
-      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnKeepRight(context).what(_qaItem));
-    }
-    function keepRightSaveSection(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      const isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
-      let saveSection = selection2.selectAll(".qa-save").data(
-        isShown ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      saveSection.exit().remove();
-      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
-      saveSectionEnter.append("h4").attr("class", ".qa-save-header").call(_t.append("QA.keepRight.comment"));
-      saveSectionEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("QA.keepRight.comment_placeholder")).attr("maxlength", 1e3).property("value", (d) => d.newComment || d.comment).call(utilNoAuto).on("input", changeInput).on("blur", changeInput);
-      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
-      function changeInput() {
-        const input = select_default2(this);
-        let val = input.property("value").trim();
-        if (val === _qaItem.comment) {
-          val = void 0;
-        }
-        _qaItem = _qaItem.update({ newComment: val });
-        const qaService = services.keepRight;
-        if (qaService) {
-          qaService.replaceItem(_qaItem);
-        }
-        saveSection.call(qaSaveButtons);
+    map2.canZoomIn = function() {
+      return map2.zoom() < maxZoom;
+    };
+    map2.zoomOut = function() {
+      zoomOut(1);
+    };
+    map2.zoomOutFurther = function() {
+      zoomOut(4);
+    };
+    map2.canZoomOut = function() {
+      return map2.zoom() > minZoom2;
+    };
+    map2.center = function(loc2) {
+      if (!arguments.length) {
+        return projection2.invert(pxCenter());
       }
-    }
-    function qaSaveButtons(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d) => d.status + d.id);
-      buttonSection.exit().remove();
-      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("QA.keepRight.save_comment"));
-      buttonEnter.append("button").attr("class", "button close-button action");
-      buttonEnter.append("button").attr("class", "button ignore-button action");
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".comment-button").attr("disabled", (d) => d.newComment ? null : true).on("click.comment", function(d3_event, d) {
-        this.blur();
-        const qaService = services.keepRight;
-        if (qaService) {
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
-        }
-      });
-      buttonSection.select(".close-button").html((d) => {
-        const andComment = d.newComment ? "_comment" : "";
-        return _t.html(`QA.keepRight.close${andComment}`);
-      }).on("click.close", function(d3_event, d) {
-        this.blur();
-        const qaService = services.keepRight;
-        if (qaService) {
-          d.newStatus = "ignore_t";
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
-        }
-      });
-      buttonSection.select(".ignore-button").html((d) => {
-        const andComment = d.newComment ? "_comment" : "";
-        return _t.html(`QA.keepRight.ignore${andComment}`);
-      }).on("click.ignore", function(d3_event, d) {
-        this.blur();
-        const qaService = services.keepRight;
-        if (qaService) {
-          d.newStatus = "ignore";
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
-        }
-      });
-    }
-    keepRightEditor.error = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return keepRightEditor;
+      if (setCenterZoom(loc2, map2.zoom())) {
+        dispatch14.call("move", this, map2);
+      }
+      scheduleRedraw();
+      return map2;
     };
-    return utilRebind(keepRightEditor, dispatch10, "on");
-  }
-
-  // modules/ui/lasso.js
-  function uiLasso(context) {
-    var group, polygon2;
-    lasso.coordinates = [];
-    function lasso(selection2) {
-      context.container().classed("lasso", true);
-      group = selection2.append("g").attr("class", "lasso hide");
-      polygon2 = group.append("path").attr("class", "lasso-path");
-      group.call(uiToggle(true));
-    }
-    function draw() {
-      if (polygon2) {
-        polygon2.data([lasso.coordinates]).attr("d", function(d) {
-          return "M" + d.join(" L") + " Z";
-        });
+    map2.unobscuredCenterZoomEase = function(loc, zoom) {
+      var offset = map2.unobscuredOffsetPx();
+      var proj = geoRawMercator().transform(projection2.transform());
+      proj.scale(geoZoomToScale(zoom, TILESIZE));
+      var locPx = proj(loc);
+      var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
+      var offsetLoc = proj.invert(offsetLocPx);
+      map2.centerZoomEase(offsetLoc, zoom);
+    };
+    map2.unobscuredOffsetPx = function() {
+      var openPane = context.container().select(".map-panes .map-pane.shown");
+      if (!openPane.empty()) {
+        return [openPane.node().offsetWidth / 2, 0];
       }
-    }
-    lasso.extent = function() {
-      return lasso.coordinates.reduce(function(extent, point) {
-        return extent.extend(geoExtent(point));
-      }, geoExtent());
+      return [0, 0];
     };
-    lasso.p = function(_) {
-      if (!arguments.length)
-        return lasso;
-      lasso.coordinates.push(_);
-      draw();
-      return lasso;
+    map2.zoom = function(z2) {
+      if (!arguments.length) {
+        return Math.max(geoScaleToZoom(projection2.scale(), TILESIZE), 0);
+      }
+      if (z2 < _minzoom) {
+        surface.interrupt();
+        dispatch14.call("hitMinZoom", this, map2);
+        z2 = context.minEditableZoom();
+      }
+      if (setCenterZoom(map2.center(), z2)) {
+        dispatch14.call("move", this, map2);
+      }
+      scheduleRedraw();
+      return map2;
     };
-    lasso.close = function() {
-      if (group) {
-        group.call(uiToggle(false, function() {
-          select_default2(this).remove();
-        }));
+    map2.centerZoom = function(loc2, z2) {
+      if (setCenterZoom(loc2, z2)) {
+        dispatch14.call("move", this, map2);
       }
-      context.container().classed("lasso", false);
+      scheduleRedraw();
+      return map2;
     };
-    return lasso;
-  }
-
-  // modules/ui/note_comments.js
-  function uiNoteComments() {
-    var _note;
-    function noteComments(selection2) {
-      if (_note.isNew())
-        return;
-      var comments = selection2.selectAll(".comments-container").data([0]);
-      comments = comments.enter().append("div").attr("class", "comments-container").merge(comments);
-      var commentEnter = comments.selectAll(".comment").data(_note.comments).enter().append("div").attr("class", "comment");
-      commentEnter.append("div").attr("class", function(d) {
-        return "comment-avatar user-" + d.uid;
-      }).call(svgIcon("#iD-icon-avatar", "comment-avatar-icon"));
-      var mainEnter = commentEnter.append("div").attr("class", "comment-main");
-      var metadataEnter = mainEnter.append("div").attr("class", "comment-metadata");
-      metadataEnter.append("div").attr("class", "comment-author").each(function(d) {
-        var selection3 = select_default2(this);
-        var osm = services.osm;
-        if (osm && d.user) {
-          selection3 = selection3.append("a").attr("class", "comment-author-link").attr("href", osm.userURL(d.user)).attr("target", "_blank");
-        }
-        if (d.user) {
-          selection3.text(d.user);
-        } else {
-          selection3.call(_t.append("note.anonymous"));
-        }
-      });
-      metadataEnter.append("div").attr("class", "comment-date").html(function(d) {
-        return _t.html("note.status." + d.action, { when: localeDateString2(d.date) });
-      });
-      mainEnter.append("div").attr("class", "comment-text").html(function(d) {
-        return d.html;
-      }).selectAll("a").attr("rel", "noopener nofollow").attr("target", "_blank");
-      comments.call(replaceAvatars);
-    }
-    function replaceAvatars(selection2) {
-      var showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
-      var osm = services.osm;
-      if (showThirdPartyIcons !== "true" || !osm)
-        return;
-      var uids = {};
-      _note.comments.forEach(function(d) {
-        if (d.uid)
-          uids[d.uid] = true;
-      });
-      Object.keys(uids).forEach(function(uid) {
-        osm.loadUser(uid, function(err, user) {
-          if (!user || !user.image_url)
-            return;
-          selection2.selectAll(".comment-avatar.user-" + uid).html("").append("img").attr("class", "icon comment-avatar-icon").attr("src", user.image_url).attr("alt", user.display_name);
-        });
-      });
-    }
-    function localeDateString2(s) {
-      if (!s)
-        return null;
-      var options2 = { day: "numeric", month: "short", year: "numeric" };
-      s = s.replace(/-/g, "/");
-      var d = new Date(s);
-      if (isNaN(d.getTime()))
-        return null;
-      return d.toLocaleDateString(_mainLocalizer.localeCode(), options2);
-    }
-    noteComments.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteComments;
+    map2.zoomTo = function(entities) {
+      if (!isArray_default(entities)) {
+        entities = [entities];
+      }
+      if (entities.length === 0) return map2;
+      var extent = entities.map((entity) => entity.extent(context.graph())).reduce((a2, b2) => a2.extend(b2));
+      if (!isFinite(extent.area())) return map2;
+      var z2 = clamp2(map2.trimmedExtentZoom(extent), 0, 20);
+      return map2.centerZoom(extent.center(), z2);
     };
-    return noteComments;
-  }
-
-  // modules/ui/note_header.js
-  function uiNoteHeader() {
-    var _note;
-    function noteHeader(selection2) {
-      var header = selection2.selectAll(".note-header").data(
-        _note ? [_note] : [],
-        function(d) {
-          return d.status + d.id;
-        }
+    map2.centerEase = function(loc2, duration) {
+      duration = duration || 250;
+      setCenterZoom(loc2, map2.zoom(), duration);
+      return map2;
+    };
+    map2.zoomEase = function(z2, duration) {
+      duration = duration || 250;
+      setCenterZoom(map2.center(), z2, duration, false);
+      return map2;
+    };
+    map2.centerZoomEase = function(loc2, z2, duration) {
+      duration = duration || 250;
+      setCenterZoom(loc2, z2, duration, false);
+      return map2;
+    };
+    map2.transformEase = function(t2, duration) {
+      duration = duration || 250;
+      setTransform(
+        t2,
+        duration,
+        false
+        /* don't force */
       );
-      header.exit().remove();
-      var headerEnter = header.enter().append("div").attr("class", "note-header");
-      var iconEnter = headerEnter.append("div").attr("class", function(d) {
-        return "note-header-icon " + d.status;
-      }).classed("new", function(d) {
-        return d.id < 0;
-      });
-      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-note", "note-fill"));
-      iconEnter.each(function(d) {
-        var statusIcon;
-        if (d.id < 0) {
-          statusIcon = "#iD-icon-plus";
-        } else if (d.status === "open") {
-          statusIcon = "#iD-icon-close";
-        } else {
-          statusIcon = "#iD-icon-apply";
-        }
-        iconEnter.append("div").attr("class", "note-icon-annotation").attr("title", _t("icons.close")).call(svgIcon(statusIcon, "icon-annotation"));
-      });
-      headerEnter.append("div").attr("class", "note-header-label").html(function(d) {
-        if (_note.isNew()) {
-          return _t.html("note.new");
-        }
-        return _t.html("note.note") + " " + d.id + " " + (d.status === "closed" ? _t.html("note.closed") : "");
+      return map2;
+    };
+    map2.zoomToEase = function(obj, duration) {
+      var extent;
+      if (Array.isArray(obj)) {
+        obj.forEach(function(entity) {
+          var entityExtent = entity.extent(context.graph());
+          if (!extent) {
+            extent = entityExtent;
+          } else {
+            extent = extent.extend(entityExtent);
+          }
+        });
+      } else {
+        extent = obj.extent(context.graph());
+      }
+      if (!isFinite(extent.area())) return map2;
+      var z2 = clamp2(map2.trimmedExtentZoom(extent), 0, 20);
+      return map2.centerZoomEase(extent.center(), z2, duration);
+    };
+    map2.startEase = function() {
+      utilBindOnce(surface, _pointerPrefix + "down.ease", function() {
+        map2.cancelEase();
       });
+      return map2;
+    };
+    map2.cancelEase = function() {
+      _selection.interrupt();
+      return map2;
+    };
+    map2.extent = function(val) {
+      if (!arguments.length) {
+        return new geoExtent(
+          projection2.invert([0, _dimensions[1]]),
+          projection2.invert([_dimensions[0], 0])
+        );
+      } else {
+        var extent = geoExtent(val);
+        map2.centerZoom(extent.center(), map2.extentZoom(extent));
+      }
+    };
+    map2.trimmedExtent = function(val) {
+      if (!arguments.length) {
+        var headerY = 71;
+        var footerY = 30;
+        var pad2 = 10;
+        return new geoExtent(
+          projection2.invert([pad2, _dimensions[1] - footerY - pad2]),
+          projection2.invert([_dimensions[0] - pad2, headerY + pad2])
+        );
+      } else {
+        var extent = geoExtent(val);
+        map2.centerZoom(extent.center(), map2.trimmedExtentZoom(extent));
+      }
+    };
+    function calcExtentZoom(extent, dim) {
+      var tl = projection2([extent[0][0], extent[1][1]]);
+      var br2 = projection2([extent[1][0], extent[0][1]]);
+      var hFactor = (br2[0] - tl[0]) / dim[0];
+      var vFactor = (br2[1] - tl[1]) / dim[1];
+      var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
+      var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
+      var newZoom = map2.zoom() - Math.max(hZoomDiff, vZoomDiff);
+      return newZoom;
     }
-    noteHeader.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteHeader;
+    map2.extentZoom = function(val) {
+      return calcExtentZoom(geoExtent(val), _dimensions);
     };
-    return noteHeader;
-  }
-
-  // modules/ui/note_report.js
-  function uiNoteReport() {
-    var _note;
-    function noteReport(selection2) {
-      var url;
-      if (services.osm && _note instanceof osmNote && !_note.isNew()) {
-        url = services.osm.noteReportURL(_note);
+    map2.trimmedExtentZoom = function(val) {
+      var trimY = 120;
+      var trimX = 40;
+      var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
+      return calcExtentZoom(geoExtent(val), trimmed);
+    };
+    map2.withinEditableZoom = function() {
+      return map2.zoom() >= context.minEditableZoom();
+    };
+    map2.isInWideSelection = function() {
+      return !map2.withinEditableZoom() && context.selectedIDs().length;
+    };
+    map2.editableDataEnabled = function(skipZoomCheck) {
+      var layer = context.layers().layer("osm");
+      if (!layer || !layer.enabled()) return false;
+      return skipZoomCheck || map2.withinEditableZoom();
+    };
+    map2.notesEditable = function() {
+      var layer = context.layers().layer("notes");
+      if (!layer || !layer.enabled()) return false;
+      return map2.withinEditableZoom();
+    };
+    map2.minzoom = function(val) {
+      if (!arguments.length) return _minzoom;
+      _minzoom = val;
+      return map2;
+    };
+    map2.toggleHighlightEdited = function() {
+      surface.classed("highlight-edited", !surface.classed("highlight-edited"));
+      map2.pan([0, 0]);
+      dispatch14.call("changeHighlighting", this);
+    };
+    map2.areaFillOptions = ["wireframe", "partial", "full"];
+    map2.activeAreaFill = function(val) {
+      if (!arguments.length) return corePreferences("area-fill") || "partial";
+      corePreferences("area-fill", val);
+      if (val !== "wireframe") {
+        corePreferences("area-fill-toggle", val);
       }
-      var link2 = selection2.selectAll(".note-report").data(url ? [url] : []);
-      link2.exit().remove();
-      var linkEnter = link2.enter().append("a").attr("class", "note-report").attr("target", "_blank").attr("href", function(d) {
-        return d;
-      }).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("note.report"));
+      updateAreaFill();
+      map2.pan([0, 0]);
+      dispatch14.call("changeAreaFill", this);
+      return map2;
+    };
+    map2.toggleWireframe = function() {
+      var activeFill = map2.activeAreaFill();
+      if (activeFill === "wireframe") {
+        activeFill = corePreferences("area-fill-toggle") || "partial";
+      } else {
+        activeFill = "wireframe";
+      }
+      map2.activeAreaFill(activeFill);
+    };
+    function updateAreaFill() {
+      var activeFill = map2.activeAreaFill();
+      map2.areaFillOptions.forEach(function(opt) {
+        surface.classed("fill-" + opt, Boolean(opt === activeFill));
+      });
     }
-    noteReport.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteReport;
+    map2.layers = () => drawLayers;
+    map2.doubleUpHandler = function() {
+      return _doubleUpHandler;
     };
-    return noteReport;
+    return utilRebind(map2, dispatch14, "on");
   }
 
-  // modules/ui/note_editor.js
-  function uiNoteEditor(context) {
-    var dispatch10 = dispatch_default("change");
-    var noteComments = uiNoteComments(context);
-    var noteHeader = uiNoteHeader();
-    var _note;
-    var _newNote;
-    function noteEditor(selection2) {
-      var header = selection2.selectAll(".header").data([0]);
-      var headerEnter = header.enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
-        context.enter(modeBrowse(context));
-      }).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("note.title"));
-      var body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      var editor = body.selectAll(".note-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section note-editor").merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
-      var footer = selection2.selectAll(".footer").data([0]);
-      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOSM(context).what(_note)).call(uiNoteReport(context).note(_note));
-      var osm = services.osm;
-      if (osm) {
-        osm.on("change.note-save", function() {
-          selection2.call(noteEditor);
-        });
-      }
+  // modules/renderer/photos.js
+  function rendererPhotos(context) {
+    var dispatch14 = dispatch_default("change");
+    var _layerIDs = ["streetside", "mapillary", "mapillary-map-features", "mapillary-signs", "kartaview", "mapilio", "vegbilder", "panoramax"];
+    var _allPhotoTypes = ["flat", "panoramic"];
+    var _shownPhotoTypes = _allPhotoTypes.slice();
+    var _dateFilters = ["fromDate", "toDate"];
+    var _fromDate;
+    var _toDate;
+    var _usernames;
+    function photos() {
     }
-    function noteSaveSection(selection2) {
-      var isSelected = _note && _note.id === context.selectedNoteID();
-      var noteSave = selection2.selectAll(".note-save").data(isSelected ? [_note] : [], function(d) {
-        return d.status + d.id;
-      });
-      noteSave.exit().remove();
-      var noteSaveEnter = noteSave.enter().append("div").attr("class", "note-save save-section cf");
-      noteSaveEnter.append("h4").attr("class", ".note-save-header").html(function() {
-        return _note.isNew() ? _t.html("note.newDescription") : _t.html("note.newComment");
+    function updateStorage() {
+      if (window.mocha) return;
+      var hash = utilStringQs(window.location.hash);
+      var enabled = context.layers().all().filter(function(d2) {
+        return _layerIDs.indexOf(d2.id) !== -1 && d2.layer && d2.layer.supported() && d2.layer.enabled();
+      }).map(function(d2) {
+        return d2.id;
       });
-      var commentTextarea = noteSaveEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("note.inputPlaceholder")).attr("maxlength", 1e3).property("value", function(d) {
-        return d.newComment;
-      }).call(utilNoAuto).on("keydown.note-input", keydown).on("input.note-input", changeInput).on("blur.note-input", changeInput);
-      if (!commentTextarea.empty() && _newNote) {
-        commentTextarea.node().focus();
+      if (enabled.length) {
+        hash.photo_overlay = enabled.join(",");
+      } else {
+        delete hash.photo_overlay;
       }
-      noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons);
-      function keydown(d3_event) {
-        if (!(d3_event.keyCode === 13 && d3_event.metaKey))
-          return;
-        var osm = services.osm;
-        if (!osm)
-          return;
-        var hasAuth = osm.authenticated();
-        if (!hasAuth)
-          return;
-        if (!_note.newComment)
-          return;
-        d3_event.preventDefault();
-        select_default2(this).on("keydown.note-input", null);
-        window.setTimeout(function() {
-          if (_note.isNew()) {
-            noteSave.selectAll(".save-button").node().focus();
-            clickSave(_note);
-          } else {
-            noteSave.selectAll(".comment-button").node().focus();
-            clickComment(_note);
-          }
-        }, 10);
+      window.location.replace("#" + utilQsString(hash, true));
+    }
+    photos.overlayLayerIDs = function() {
+      return _layerIDs;
+    };
+    photos.allPhotoTypes = function() {
+      return _allPhotoTypes;
+    };
+    photos.dateFilters = function() {
+      return _dateFilters;
+    };
+    photos.dateFilterValue = function(val) {
+      return val === _dateFilters[0] ? _fromDate : _toDate;
+    };
+    photos.setDateFilter = function(type2, val, updateUrl) {
+      var date = val && new Date(val);
+      if (date && !isNaN(date)) {
+        val = date.toISOString().slice(0, 10);
+      } else {
+        val = null;
       }
-      function changeInput() {
-        var input = select_default2(this);
-        var val = input.property("value").trim() || void 0;
-        _note = _note.update({ newComment: val });
-        var osm = services.osm;
-        if (osm) {
-          osm.replaceNote(_note);
+      if (type2 === _dateFilters[0]) {
+        _fromDate = val;
+        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
+          _toDate = _fromDate;
         }
-        noteSave.call(noteSaveButtons);
       }
-    }
-    function userDetails(selection2) {
-      var detailSection = selection2.selectAll(".detail-section").data([0]);
-      detailSection = detailSection.enter().append("div").attr("class", "detail-section").merge(detailSection);
-      var osm = services.osm;
-      if (!osm)
-        return;
-      var hasAuth = osm.authenticated();
-      var authWarning = detailSection.selectAll(".auth-warning").data(hasAuth ? [] : [0]);
-      authWarning.exit().transition().duration(200).style("opacity", 0).remove();
-      var authEnter = authWarning.enter().insert("div", ".tag-reference-body").attr("class", "field-warning auth-warning").style("opacity", 0);
-      authEnter.call(svgIcon("#iD-icon-alert", "inline"));
-      authEnter.append("span").call(_t.append("note.login"));
-      authEnter.append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.note-login", function(d3_event) {
-        d3_event.preventDefault();
-        osm.authenticate();
-      });
-      authEnter.transition().duration(200).style("opacity", 1);
-      var prose = detailSection.selectAll(".note-save-prose").data(hasAuth ? [0] : []);
-      prose.exit().remove();
-      prose = prose.enter().append("p").attr("class", "note-save-prose").call(_t.append("note.upload_explanation")).merge(prose);
-      osm.userDetails(function(err, user) {
-        if (err)
-          return;
-        var userLink = select_default2(document.createElement("div"));
-        if (user.image_url) {
-          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
+      if (type2 === _dateFilters[1]) {
+        _toDate = val;
+        if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
+          _fromDate = _toDate;
         }
-        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
-        prose.html(_t.html("note.upload_explanation_with_user", { user: { html: userLink.html() } }));
-      });
-    }
-    function noteSaveButtons(selection2) {
-      var osm = services.osm;
-      var hasAuth = osm && osm.authenticated();
-      var isSelected = _note && _note.id === context.selectedNoteID();
-      var buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_note] : [], function(d) {
-        return d.status + d.id;
-      });
-      buttonSection.exit().remove();
-      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      if (_note.isNew()) {
-        buttonEnter.append("button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
-        buttonEnter.append("button").attr("class", "button save-button action").call(_t.append("note.save"));
-      } else {
-        buttonEnter.append("button").attr("class", "button status-button action");
-        buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("note.comment"));
       }
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
-      buttonSection.select(".save-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
-      buttonSection.select(".status-button").attr("disabled", hasAuth ? null : true).html(function(d) {
-        var action = d.status === "open" ? "close" : "open";
-        var andComment = d.newComment ? "_comment" : "";
-        return _t.html("note." + action + andComment);
-      }).on("click.status", clickStatus);
-      buttonSection.select(".comment-button").attr("disabled", isSaveDisabled).on("click.comment", clickComment);
-      function isSaveDisabled(d) {
-        return hasAuth && d.status === "open" && d.newComment ? null : true;
+      dispatch14.call("change", this);
+      if (updateUrl) {
+        var rangeString;
+        if (_fromDate || _toDate) {
+          rangeString = (_fromDate || "") + "_" + (_toDate || "");
+        }
+        setUrlFilterValue("photo_dates", rangeString);
       }
-    }
-    function clickCancel(d3_event, d) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        osm.removeNote(d);
+    };
+    photos.setUsernameFilter = function(val, updateUrl) {
+      if (val && typeof val === "string") val = val.replace(/;/g, ",").split(",");
+      if (val) {
+        val = val.map((d2) => d2.trim()).filter(Boolean);
+        if (!val.length) {
+          val = null;
+        }
       }
-      context.enter(modeBrowse(context));
-      dispatch10.call("change");
-    }
-    function clickSave(d3_event, d) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        osm.postNoteCreate(d, function(err, note) {
-          dispatch10.call("change", note);
-        });
+      _usernames = val;
+      dispatch14.call("change", this);
+      if (updateUrl) {
+        var hashString;
+        if (_usernames) {
+          hashString = _usernames.join(",");
+        }
+        setUrlFilterValue("photo_username", hashString);
       }
-    }
-    function clickStatus(d3_event, d) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        var setStatus = d.status === "open" ? "closed" : "open";
-        osm.postNoteUpdate(d, setStatus, function(err, note) {
-          dispatch10.call("change", note);
-        });
+    };
+    function setUrlFilterValue(property, val) {
+      if (!window.mocha) {
+        var hash = utilStringQs(window.location.hash);
+        if (val) {
+          if (hash[property] === val) return;
+          hash[property] = val;
+        } else {
+          if (!(property in hash)) return;
+          delete hash[property];
+        }
+        window.location.replace("#" + utilQsString(hash, true));
       }
     }
-    function clickComment(d3_event, d) {
-      this.blur();
-      var osm = services.osm;
-      if (osm) {
-        osm.postNoteUpdate(d, d.status, function(err, note) {
-          dispatch10.call("change", note);
-        });
-      }
+    function showsLayer(id2) {
+      var layer = context.layers().layer(id2);
+      return layer && layer.supported() && layer.enabled();
     }
-    noteEditor.note = function(val) {
-      if (!arguments.length)
-        return _note;
-      _note = val;
-      return noteEditor;
+    photos.shouldFilterByDate = function() {
+      return showsLayer("mapillary") || showsLayer("kartaview") || showsLayer("streetside") || showsLayer("vegbilder") || showsLayer("panoramax");
     };
-    noteEditor.newNote = function(val) {
-      if (!arguments.length)
-        return _newNote;
-      _newNote = val;
-      return noteEditor;
+    photos.shouldFilterByPhotoType = function() {
+      return showsLayer("mapillary") || showsLayer("streetside") && showsLayer("kartaview") || showsLayer("vegbilder") || showsLayer("panoramax");
     };
-    return utilRebind(noteEditor, dispatch10, "on");
-  }
-
-  // modules/ui/source_switch.js
-  function uiSourceSwitch(context) {
-    var keys;
-    function click(d3_event) {
-      d3_event.preventDefault();
-      var osm = context.connection();
-      if (!osm)
-        return;
-      if (context.inIntro())
-        return;
-      if (context.history().hasChanges() && !window.confirm(_t("source_switch.lose_changes")))
-        return;
-      var isLive = select_default2(this).classed("live");
-      isLive = !isLive;
-      context.enter(modeBrowse(context));
-      context.history().clearSaved();
-      context.flush();
-      select_default2(this).html(isLive ? _t.html("source_switch.live") : _t.html("source_switch.dev")).classed("live", isLive).classed("chip", isLive);
-      osm.switch(isLive ? keys[0] : keys[1]);
-    }
-    var sourceSwitch = function(selection2) {
-      selection2.append("a").attr("href", "#").call(_t.append("source_switch.live")).attr("class", "live chip").on("click", click);
+    photos.shouldFilterByUsername = function() {
+      return !showsLayer("mapillary") && showsLayer("kartaview") && !showsLayer("streetside") || showsLayer("panoramax");
     };
-    sourceSwitch.keys = function(_) {
-      if (!arguments.length)
-        return keys;
-      keys = _;
-      return sourceSwitch;
+    photos.showsPhotoType = function(val) {
+      if (!photos.shouldFilterByPhotoType()) return true;
+      return _shownPhotoTypes.indexOf(val) !== -1;
     };
-    return sourceSwitch;
-  }
-
-  // modules/ui/spinner.js
-  function uiSpinner(context) {
-    var osm = context.connection();
-    return function(selection2) {
-      var img = selection2.append("img").attr("src", context.imagePath("loader-black.gif")).style("opacity", 0);
-      if (osm) {
-        osm.on("loading.spinner", function() {
-          img.transition().style("opacity", 1);
-        }).on("loaded.spinner", function() {
-          img.transition().style("opacity", 0);
-        });
-      }
+    photos.showsFlat = function() {
+      return photos.showsPhotoType("flat");
     };
-  }
-
-  // modules/ui/sections/privacy.js
-  function uiSectionPrivacy(context) {
-    let section = uiSection("preferences-third-party", context).label(() => _t.append("preferences.privacy.title")).disclosureContent(renderDisclosureContent);
-    function renderDisclosureContent(selection2) {
-      selection2.selectAll(".privacy-options-list").data([0]).enter().append("ul").attr("class", "layer-list privacy-options-list");
-      let thirdPartyIconsEnter = selection2.select(".privacy-options-list").selectAll(".privacy-third-party-icons-item").data([corePreferences("preferences.privacy.thirdpartyicons") || "true"]).enter().append("li").attr("class", "privacy-third-party-icons-item").append("label").call(
-        uiTooltip().title(() => _t.append("preferences.privacy.third_party_icons.tooltip")).placement("bottom")
-      );
-      thirdPartyIconsEnter.append("input").attr("type", "checkbox").on("change", (d3_event, d) => {
-        d3_event.preventDefault();
-        corePreferences("preferences.privacy.thirdpartyicons", d === "true" ? "false" : "true");
-      });
-      thirdPartyIconsEnter.append("span").call(_t.append("preferences.privacy.third_party_icons.description"));
-      selection2.selectAll(".privacy-third-party-icons-item").classed("active", (d) => d === "true").select("input").property("checked", (d) => d === "true");
-      selection2.selectAll(".privacy-link").data([0]).enter().append("div").attr("class", "privacy-link").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/release/PRIVACY.md").append("span").call(_t.append("preferences.privacy.privacy_link"));
-    }
-    corePreferences.onChange("preferences.privacy.thirdpartyicons", section.reRender);
-    return section;
-  }
-
-  // modules/ui/splash.js
-  function uiSplash(context) {
-    return (selection2) => {
-      if (context.history().hasRestorableChanges())
-        return;
-      let updateMessage = "";
-      const sawPrivacyVersion = corePreferences("sawPrivacyVersion");
-      let showSplash = !corePreferences("sawSplash");
-      if (sawPrivacyVersion !== context.privacyVersion) {
-        updateMessage = _t("splash.privacy_update");
-        showSplash = true;
+    photos.showsPanoramic = function() {
+      return photos.showsPhotoType("panoramic");
+    };
+    photos.fromDate = function() {
+      return _fromDate;
+    };
+    photos.toDate = function() {
+      return _toDate;
+    };
+    photos.togglePhotoType = function(val) {
+      var index = _shownPhotoTypes.indexOf(val);
+      if (index !== -1) {
+        _shownPhotoTypes.splice(index, 1);
+      } else {
+        _shownPhotoTypes.push(val);
       }
-      if (!showSplash)
-        return;
-      corePreferences("sawSplash", true);
-      corePreferences("sawPrivacyVersion", context.privacyVersion);
-      _mainFileFetcher.get("intro_graph");
-      let modalSelection = uiModal(selection2);
-      modalSelection.select(".modal").attr("class", "modal-splash modal");
-      let introModal = modalSelection.select(".content").append("div").attr("class", "fillL");
-      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("splash.welcome"));
-      let modalSection = introModal.append("div").attr("class", "modal-section");
-      modalSection.append("p").html(_t.html("splash.text", {
-        version: context.version,
-        website: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">' + _t.html("splash.changelog") + "</a>" },
-        github: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>' }
-      }));
-      modalSection.append("p").html(_t.html("splash.privacy", {
-        updateMessage,
-        privacyLink: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t("splash.privacy_policy") + "</a>" }
-      }));
-      uiSectionPrivacy(context).label(() => _t.append("splash.privacy_settings")).render(modalSection);
-      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
-      let walkthrough = buttonWrap.append("button").attr("class", "walkthrough").on("click", () => {
-        context.container().call(uiIntro(context));
-        modalSelection.close();
-      });
-      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
-      walkthrough.append("div").call(_t.append("splash.walkthrough"));
-      let startEditing = buttonWrap.append("button").attr("class", "start-editing").on("click", modalSelection.close);
-      startEditing.append("svg").attr("class", "logo logo-features").append("use").attr("xlink:href", "#iD-logo-features");
-      startEditing.append("div").call(_t.append("splash.start"));
-      modalSelection.select("button.close").attr("class", "hide");
+      dispatch14.call("change", this);
+      return photos;
     };
-  }
-
-  // modules/ui/status.js
-  function uiStatus(context) {
-    var osm = context.connection();
-    return function(selection2) {
-      if (!osm)
-        return;
-      function update(err, apiStatus) {
-        selection2.html("");
-        if (err) {
-          if (apiStatus === "connectionSwitched") {
-            return;
-          } else if (apiStatus === "rateLimited") {
-            selection2.call(_t.append("osm_api_status.message.rateLimit")).append("a").attr("href", "#").attr("class", "api-status-login").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.login", function(d3_event) {
-              d3_event.preventDefault();
-              osm.authenticate();
-            });
-          } else {
-            var throttledRetry = throttle_default(function() {
-              context.loadTiles(context.projection);
-              osm.reloadApiStatus();
-            }, 2e3);
-            selection2.call(_t.append("osm_api_status.message.error", { suffix: " " })).append("a").attr("href", "#").call(_t.append("osm_api_status.retry")).on("click.retry", function(d3_event) {
-              d3_event.preventDefault();
-              throttledRetry();
+    photos.usernames = function() {
+      return _usernames;
+    };
+    photos.init = function() {
+      var hash = utilStringQs(window.location.hash);
+      if (hash.photo_dates) {
+        var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
+        this.setDateFilter("fromDate", parts && parts.length >= 2 && parts[1], false);
+        this.setDateFilter("toDate", parts && parts.length >= 3 && parts[2], false);
+      }
+      if (hash.photo_username) {
+        this.setUsernameFilter(hash.photo_username, false);
+      }
+      if (hash.photo_overlay) {
+        var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ",").split(",");
+        hashOverlayIDs.forEach(function(id2) {
+          if (id2 === "openstreetcam") id2 = "kartaview";
+          var layer2 = _layerIDs.indexOf(id2) !== -1 && context.layers().layer(id2);
+          if (layer2 && !layer2.enabled()) layer2.enabled(true);
+        });
+      }
+      if (hash.photo) {
+        var photoIds = hash.photo.replace(/;/g, ",").split(",");
+        var photoId = photoIds.length && photoIds[0].trim();
+        var results = /(.*)\/(.*)/g.exec(photoId);
+        if (results && results.length >= 3) {
+          var serviceId = results[1];
+          if (serviceId === "openstreetcam") serviceId = "kartaview";
+          var photoKey = results[2];
+          var service = services[serviceId];
+          if (service && service.ensureViewerLoaded) {
+            var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
+            if (layer && !layer.enabled()) layer.enabled(true);
+            var baselineTime = Date.now();
+            service.on("loadedImages.rendererPhotos", function() {
+              if (Date.now() - baselineTime > 45e3) {
+                service.on("loadedImages.rendererPhotos", null);
+                return;
+              }
+              if (!service.cachedImage(photoKey)) return;
+              service.on("loadedImages.rendererPhotos", null);
+              service.ensureViewerLoaded(context).then(function() {
+                service.selectImage(context, photoKey).showViewer(context);
+              });
             });
           }
-        } else if (apiStatus === "readonly") {
-          selection2.call(_t.append("osm_api_status.message.readonly"));
-        } else if (apiStatus === "offline") {
-          selection2.call(_t.append("osm_api_status.message.offline"));
         }
-        selection2.attr("class", "api-status " + (err ? "error" : apiStatus));
       }
-      osm.on("apiStatusChange.uiStatus", update);
-      context.history().on("storage_error", () => {
-        selection2.selectAll("span.local-storage-full").remove();
-        selection2.append("span").attr("class", "local-storage-full").call(_t.append("osm_api_status.message.local_storage_full"));
-        selection2.classed("error", true);
-      });
-      window.setInterval(function() {
-        osm.reloadApiStatus();
-      }, 9e4);
-      osm.reloadApiStatus();
+      context.layers().on("change.rendererPhotos", updateStorage);
     };
+    return utilRebind(photos, dispatch14, "on");
   }
 
-  // node_modules/osm-community-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\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()
-    );
-  }
-
-  // node_modules/osm-community-index/lib/resolve_strings.js
-  function resolveStrings(item, defaults2, localizerFn) {
-    let itemStrings = Object.assign({}, item.strings);
-    let defaultStrings = Object.assign({}, defaults2[item.type]);
-    const anyToken = new RegExp(/(\{\w+\})/, "gi");
-    if (localizerFn) {
-      if (itemStrings.community) {
-        const communityID = simplify2(itemStrings.community);
-        itemStrings.community = localizerFn(`_communities.${communityID}`);
+  // modules/ui/map_in_map.js
+  function uiMapInMap(context) {
+    function mapInMap(selection2) {
+      var backgroundLayer = rendererTileLayer(context);
+      var overlayLayers = {};
+      var projection2 = geoRawMercator();
+      var dataLayer = svgData(projection2, context).showLabels(false);
+      var debugLayer = svgDebug(projection2, context);
+      var zoom = zoom_default2().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on("start", zoomStarted).on("zoom", zoomed).on("end", zoomEnded);
+      var wrap2 = select_default2(null);
+      var tiles = select_default2(null);
+      var viewport = select_default2(null);
+      var _isTransformed = false;
+      var _isHidden = true;
+      var _skipEvents = false;
+      var _gesture = null;
+      var _zDiff = 6;
+      var _dMini;
+      var _cMini;
+      var _tStart;
+      var _tCurr;
+      var _timeoutID;
+      function zoomStarted() {
+        if (_skipEvents) return;
+        _tStart = _tCurr = projection2.transform();
+        _gesture = null;
       }
-      ["name", "description", "extendedDescription"].forEach((prop) => {
-        if (defaultStrings[prop])
-          defaultStrings[prop] = localizerFn(`_defaults.${item.type}.${prop}`);
-        if (itemStrings[prop])
-          itemStrings[prop] = localizerFn(`${item.id}.${prop}`);
-      });
-    }
-    let replacements = {
-      account: item.account,
-      community: itemStrings.community,
-      signupUrl: itemStrings.signupUrl,
-      url: itemStrings.url
-    };
-    if (!replacements.signupUrl) {
-      replacements.signupUrl = resolve(itemStrings.signupUrl || defaultStrings.signupUrl);
-    }
-    if (!replacements.url) {
-      replacements.url = resolve(itemStrings.url || defaultStrings.url);
-    }
-    let resolved = {
-      name: resolve(itemStrings.name || defaultStrings.name),
-      url: resolve(itemStrings.url || defaultStrings.url),
-      signupUrl: resolve(itemStrings.signupUrl || defaultStrings.signupUrl),
-      description: resolve(itemStrings.description || defaultStrings.description),
-      extendedDescription: resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription)
-    };
-    resolved.nameHTML = linkify(resolved.url, resolved.name);
-    resolved.urlHTML = linkify(resolved.url);
-    resolved.signupUrlHTML = linkify(resolved.signupUrl);
-    resolved.descriptionHTML = resolve(itemStrings.description || defaultStrings.description, true);
-    resolved.extendedDescriptionHTML = resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription, true);
-    return resolved;
-    function resolve(s, addLinks) {
-      if (!s)
-        return void 0;
-      let result = s;
-      for (let key in replacements) {
-        const token = `{${key}}`;
-        const regex = new RegExp(token, "g");
-        if (regex.test(result)) {
-          let replacement = replacements[key];
-          if (!replacement) {
-            throw new Error(`Cannot resolve token: ${token}`);
-          } else {
-            if (addLinks && (key === "signupUrl" || key === "url")) {
-              replacement = linkify(replacement);
-            }
-            result = result.replace(regex, replacement);
-          }
+      function zoomed(d3_event) {
+        if (_skipEvents) return;
+        var x2 = d3_event.transform.x;
+        var y2 = d3_event.transform.y;
+        var k2 = d3_event.transform.k;
+        var isZooming = k2 !== _tStart.k;
+        var isPanning = x2 !== _tStart.x || y2 !== _tStart.y;
+        if (!isZooming && !isPanning) {
+          return;
         }
-      }
-      const leftovers = result.match(anyToken);
-      if (leftovers) {
-        throw new Error(`Cannot resolve tokens: ${leftovers}`);
-      }
-      if (addLinks && item.type === "reddit") {
-        result = result.replace(/(\/r\/\w+\/*)/i, (match) => linkify(resolved.url, match));
-      }
-      return result;
-    }
-    function linkify(url, text2) {
-      if (!url)
-        return void 0;
-      text2 = text2 || url;
-      return `<a target="_blank" href="${url}">${text2}</a>`;
-    }
-  }
-
-  // modules/ui/success.js
-  var _oci = null;
-  function uiSuccess(context) {
-    const MAXEVENTS = 2;
-    const dispatch10 = dispatch_default("cancel");
-    let _changeset2;
-    let _location;
-    ensureOSMCommunityIndex();
-    function ensureOSMCommunityIndex() {
-      const data = _mainFileFetcher;
-      return Promise.all([
-        data.get("oci_features"),
-        data.get("oci_resources"),
-        data.get("oci_defaults")
-      ]).then((vals) => {
-        if (_oci)
-          return _oci;
-        if (vals[0] && Array.isArray(vals[0].features)) {
-          _mainLocations.mergeCustomGeoJSON(vals[0]);
+        if (!_gesture) {
+          _gesture = isZooming ? "zoom" : "pan";
         }
-        let ociResources = Object.values(vals[1].resources);
-        if (ociResources.length) {
-          return _mainLocations.mergeLocationSets(ociResources).then(() => {
-            _oci = {
-              resources: ociResources,
-              defaults: vals[2].defaults
-            };
-            return _oci;
-          });
+        var tMini = projection2.transform();
+        var tX, tY, scale;
+        if (_gesture === "zoom") {
+          scale = k2 / tMini.k;
+          tX = (_cMini[0] / scale - _cMini[0]) * scale;
+          tY = (_cMini[1] / scale - _cMini[1]) * scale;
         } else {
-          _oci = {
-            resources: [],
-            defaults: vals[2].defaults
-          };
-          return _oci;
+          k2 = tMini.k;
+          scale = 1;
+          tX = x2 - tMini.x;
+          tY = y2 - tMini.y;
         }
-      });
-    }
-    function parseEventDate(when) {
-      if (!when)
-        return;
-      let raw = when.trim();
-      if (!raw)
-        return;
-      if (!/Z$/.test(raw)) {
-        raw += "Z";
-      }
-      const parsed = new Date(raw);
-      return new Date(parsed.toUTCString().slice(0, 25));
-    }
-    function success(selection2) {
-      let header = selection2.append("div").attr("class", "header fillL");
-      header.append("h2").call(_t.append("success.just_edited"));
-      header.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => dispatch10.call("cancel")).call(svgIcon("#iD-icon-close"));
-      let body = selection2.append("div").attr("class", "body save-success fillL");
-      let summary = body.append("div").attr("class", "save-summary");
-      summary.append("h3").call(_t.append("success.thank_you" + (_location ? "_location" : ""), { where: _location }));
-      summary.append("p").call(_t.append("success.help_html")).append("a").attr("class", "link-out").attr("target", "_blank").attr("href", _t("success.help_link_url")).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("success.help_link_text"));
-      let osm = context.connection();
-      if (!osm)
-        return;
-      let changesetURL = osm.changesetURL(_changeset2.id);
-      let table = summary.append("table").attr("class", "summary-table");
-      let row = table.append("tr").attr("class", "summary-row");
-      row.append("td").attr("class", "cell-icon summary-icon").append("a").attr("target", "_blank").attr("href", changesetURL).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", "#iD-logo-osm");
-      let summaryDetail = row.append("td").attr("class", "cell-detail summary-detail");
-      summaryDetail.append("a").attr("class", "cell-detail summary-view-on-osm").attr("target", "_blank").attr("href", changesetURL).call(_t.append("success.view_on_osm"));
-      summaryDetail.append("div").html(_t.html("success.changeset_id", {
-        changeset_id: { html: `<a href="${changesetURL}" target="_blank">${_changeset2.id}</a>` }
-      }));
-      ensureOSMCommunityIndex().then((oci) => {
-        const loc = context.map().center();
-        const validLocations = _mainLocations.locationsAt(loc);
-        let communities = [];
-        oci.resources.forEach((resource) => {
-          let area = validLocations[resource.locationSetID];
-          if (!area)
-            return;
-          const localizer = (stringID) => _t.html(`community.${stringID}`);
-          resource.resolved = resolveStrings(resource, oci.defaults, localizer);
-          communities.push({
-            area,
-            order: resource.order || 0,
-            resource
-          });
-        });
-        communities.sort((a, b) => a.area - b.area || b.order - a.order);
-        body.call(showCommunityLinks, communities.map((c) => c.resource));
-      });
-    }
-    function showCommunityLinks(selection2, resources) {
-      let communityLinks = selection2.append("div").attr("class", "save-communityLinks");
-      communityLinks.append("h3").call(_t.append("success.like_osm"));
-      let table = communityLinks.append("table").attr("class", "community-table");
-      let row = table.selectAll(".community-row").data(resources);
-      let rowEnter = row.enter().append("tr").attr("class", "community-row");
-      rowEnter.append("td").attr("class", "cell-icon community-icon").append("a").attr("target", "_blank").attr("href", (d) => d.resolved.url).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", (d) => `#community-${d.type}`);
-      let communityDetail = rowEnter.append("td").attr("class", "cell-detail community-detail");
-      communityDetail.each(showCommunityDetails);
-      communityLinks.append("div").attr("class", "community-missing").call(_t.append("success.missing")).append("a").attr("class", "link-out").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmlab/osm-community-index/issues").append("span").call(_t.append("success.tell_us"));
-    }
-    function showCommunityDetails(d) {
-      let selection2 = select_default2(this);
-      let communityID = d.id;
-      selection2.append("div").attr("class", "community-name").html(d.resolved.nameHTML);
-      selection2.append("div").attr("class", "community-description").html(d.resolved.descriptionHTML);
-      if (d.resolved.extendedDescriptionHTML || d.languageCodes && d.languageCodes.length) {
-        selection2.append("div").call(
-          uiDisclosure(context, `community-more-${d.id}`, false).expanded(false).updatePreference(false).label(() => _t.append("success.more")).content(showMore)
-        );
+        utilSetTransform(tiles, tX, tY, scale);
+        utilSetTransform(viewport, 0, 0, scale);
+        _isTransformed = true;
+        _tCurr = identity2.translate(x2, y2).scale(k2);
+        var zMain = geoScaleToZoom(context.projection.scale());
+        var zMini = geoScaleToZoom(k2);
+        _zDiff = zMain - zMini;
+        queueRedraw();
       }
-      let nextEvents = (d.events || []).map((event) => {
-        event.date = parseEventDate(event.when);
-        return event;
-      }).filter((event) => {
-        const t = event.date.getTime();
-        const now3 = 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;
-      }).slice(0, MAXEVENTS);
-      if (nextEvents.length) {
-        selection2.append("div").call(
-          uiDisclosure(context, `community-events-${d.id}`, false).expanded(false).updatePreference(false).label(_t.html("success.events")).content(showNextEvents)
-        ).select(".hide-toggle").append("span").attr("class", "badge-text").text(nextEvents.length);
+      function zoomEnded() {
+        if (_skipEvents) return;
+        if (_gesture !== "pan") return;
+        updateProjection();
+        _gesture = null;
+        context.map().center(projection2.invert(_cMini));
       }
-      function showMore(selection3) {
-        let more = selection3.selectAll(".community-more").data([0]);
-        let moreEnter = more.enter().append("div").attr("class", "community-more");
-        if (d.resolved.extendedDescriptionHTML) {
-          moreEnter.append("div").attr("class", "community-extended-description").html(d.resolved.extendedDescriptionHTML);
-        }
-        if (d.languageCodes && d.languageCodes.length) {
-          const languageList = d.languageCodes.map((code) => _mainLocalizer.languageName(code)).join(", ");
-          moreEnter.append("div").attr("class", "community-languages").call(_t.append("success.languages", { languages: languageList }));
+      function updateProjection() {
+        var loc = context.map().center();
+        var tMain = context.projection.transform();
+        var zMain = geoScaleToZoom(tMain.k);
+        var zMini = Math.max(zMain - _zDiff, 0.5);
+        var kMini = geoZoomToScale(zMini);
+        projection2.translate([tMain.x, tMain.y]).scale(kMini);
+        var point = projection2(loc);
+        var mouse = _gesture === "pan" ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
+        var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
+        var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
+        projection2.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
+        _tCurr = projection2.transform();
+        if (_isTransformed) {
+          utilSetTransform(tiles, 0, 0);
+          utilSetTransform(viewport, 0, 0);
+          _isTransformed = false;
         }
+        zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
+        _skipEvents = true;
+        wrap2.call(zoom.transform, _tCurr);
+        _skipEvents = false;
       }
-      function showNextEvents(selection3) {
-        let events = selection3.append("div").attr("class", "community-events");
-        let item = events.selectAll(".community-event").data(nextEvents);
-        let itemEnter = item.enter().append("div").attr("class", "community-event");
-        itemEnter.append("div").attr("class", "community-event-name").append("a").attr("target", "_blank").attr("href", (d2) => d2.url).text((d2) => {
-          let name = d2.name;
-          if (d2.i18n && d2.id) {
-            name = _t(`community.${communityID}.events.${d2.id}.name`, { default: name });
-          }
-          return name;
-        });
-        itemEnter.append("div").attr("class", "community-event-when").text((d2) => {
-          let options2 = { weekday: "short", day: "numeric", month: "short", year: "numeric" };
-          if (d2.date.getHours() || d2.date.getMinutes()) {
-            options2.hour = "numeric";
-            options2.minute = "numeric";
-          }
-          return d2.date.toLocaleString(_mainLocalizer.localeCode(), options2);
-        });
-        itemEnter.append("div").attr("class", "community-event-where").text((d2) => {
-          let where = d2.where;
-          if (d2.i18n && d2.id) {
-            where = _t(`community.${communityID}.events.${d2.id}.where`, { default: where });
+      function redraw() {
+        clearTimeout(_timeoutID);
+        if (_isHidden) return;
+        updateProjection();
+        var zMini = geoScaleToZoom(projection2.scale());
+        tiles = wrap2.selectAll(".map-in-map-tiles").data([0]);
+        tiles = tiles.enter().append("div").attr("class", "map-in-map-tiles").merge(tiles);
+        backgroundLayer.source(context.background().baseLayerSource()).projection(projection2).dimensions(_dMini);
+        var background = tiles.selectAll(".map-in-map-background").data([0]);
+        background.enter().append("div").attr("class", "map-in-map-background").merge(background).call(backgroundLayer);
+        var overlaySources = context.background().overlayLayerSources();
+        var activeOverlayLayers = [];
+        for (var i3 = 0; i3 < overlaySources.length; i3++) {
+          if (overlaySources[i3].validZoom(zMini)) {
+            if (!overlayLayers[i3]) overlayLayers[i3] = rendererTileLayer(context);
+            activeOverlayLayers.push(overlayLayers[i3].source(overlaySources[i3]).projection(projection2).dimensions(_dMini));
           }
-          return where;
+        }
+        var overlay = tiles.selectAll(".map-in-map-overlay").data([0]);
+        overlay = overlay.enter().append("div").attr("class", "map-in-map-overlay").merge(overlay);
+        var overlays = overlay.selectAll("div").data(activeOverlayLayers, function(d2) {
+          return d2.source().name();
         });
-        itemEnter.append("div").attr("class", "community-event-description").text((d2) => {
-          let description = d2.description;
-          if (d2.i18n && d2.id) {
-            description = _t(`community.${communityID}.events.${d2.id}.description`, { default: description });
-          }
-          return description;
+        overlays.exit().remove();
+        overlays = overlays.enter().append("div").merge(overlays).each(function(layer) {
+          select_default2(this).call(layer);
         });
+        var dataLayers = tiles.selectAll(".map-in-map-data").data([0]);
+        dataLayers.exit().remove();
+        dataLayers = dataLayers.enter().append("svg").attr("class", "map-in-map-data").merge(dataLayers).call(dataLayer).call(debugLayer);
+        if (_gesture !== "pan") {
+          var getPath = path_default(projection2);
+          var bbox2 = { type: "Polygon", coordinates: [context.map().extent().polygon()] };
+          viewport = wrap2.selectAll(".map-in-map-viewport").data([0]);
+          viewport = viewport.enter().append("svg").attr("class", "map-in-map-viewport").merge(viewport);
+          var path = viewport.selectAll(".map-in-map-bbox").data([bbox2]);
+          path.enter().append("path").attr("class", "map-in-map-bbox").merge(path).attr("d", getPath).classed("thick", function(d2) {
+            return getPath.area(d2) < 30;
+          });
+        }
+      }
+      function queueRedraw() {
+        clearTimeout(_timeoutID);
+        _timeoutID = setTimeout(function() {
+          redraw();
+        }, 750);
+      }
+      function toggle(d3_event) {
+        if (d3_event) d3_event.preventDefault();
+        _isHidden = !_isHidden;
+        context.container().select(".minimap-toggle-item").classed("active", !_isHidden).select("input").property("checked", !_isHidden);
+        if (_isHidden) {
+          wrap2.style("display", "block").style("opacity", "1").transition().duration(200).style("opacity", "0").on("end", function() {
+            selection2.selectAll(".map-in-map").style("display", "none");
+          });
+        } else {
+          wrap2.style("display", "block").style("opacity", "0").transition().duration(200).style("opacity", "1").on("end", function() {
+            redraw();
+          });
+        }
       }
+      uiMapInMap.toggle = toggle;
+      wrap2 = selection2.selectAll(".map-in-map").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "map-in-map").style("display", _isHidden ? "none" : "block").call(zoom).on("dblclick.zoom", null).merge(wrap2);
+      _dMini = [200, 150];
+      _cMini = geoVecScale(_dMini, 0.5);
+      context.map().on("drawn.map-in-map", function(drawn) {
+        if (drawn.full === true) {
+          redraw();
+        }
+      });
+      redraw();
+      context.keybinding().on(_t("background.minimap.key"), toggle);
     }
-    success.changeset = function(val) {
-      if (!arguments.length)
-        return _changeset2;
-      _changeset2 = val;
-      return success;
-    };
-    success.location = function(val) {
-      if (!arguments.length)
-        return _location;
-      _location = val;
-      return success;
-    };
-    return utilRebind(success, dispatch10, "on");
+    return mapInMap;
   }
 
-  // modules/ui/version.js
-  var sawVersion = null;
-  var isNewVersion = false;
-  var isNewUser = false;
-  function uiVersion(context) {
-    var currVersion = context.version;
-    var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
-    if (sawVersion === null && matchedVersion !== null) {
-      if (corePreferences("sawVersion")) {
-        isNewUser = false;
-        isNewVersion = corePreferences("sawVersion") !== currVersion && currVersion.indexOf("-") === -1;
-      } else {
-        isNewUser = true;
-        isNewVersion = true;
-      }
-      corePreferences("sawVersion", currVersion);
-      sawVersion = currVersion;
-    }
+  // modules/ui/notice.js
+  function uiNotice(context) {
     return function(selection2) {
-      selection2.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD").text(currVersion);
-      if (isNewVersion && !isNewUser) {
-        selection2.append("a").attr("class", "badge").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new").call(svgIcon("#maki-gift")).call(
-          uiTooltip().title(() => _t.append("version.whats_new", { version: currVersion })).placement("top").scrollContainer(context.container().select(".main-footer-wrap"))
-        );
+      var div = selection2.append("div").attr("class", "notice");
+      var button = div.append("button").attr("class", "zoom-to notice fillD").on("click", function() {
+        context.map().zoomEase(context.minEditableZoom());
+      }).on("wheel", function(d3_event) {
+        var e22 = new WheelEvent(d3_event.type, d3_event);
+        context.surface().node().dispatchEvent(e22);
+      });
+      button.call(svgIcon("#iD-icon-plus", "pre-text")).append("span").attr("class", "label").call(_t.append("zoom_in_edit"));
+      function disableTooHigh() {
+        var canEdit = context.map().zoom() >= context.minEditableZoom();
+        div.style("display", canEdit ? "none" : "block");
       }
+      context.map().on("move.notice", debounce_default(disableTooHigh, 500));
+      disableTooHigh();
     };
   }
 
-  // modules/ui/zoom.js
-  function uiZoom(context) {
-    var zooms = [{
-      id: "zoom-in",
-      icon: "iD-icon-plus",
-      title: _t.append("zoom.in"),
-      action: zoomIn,
-      disabled: function() {
-        return !context.map().canZoomIn();
-      },
-      disabledTitle: _t.append("zoom.disabled.in"),
-      key: "+"
-    }, {
-      id: "zoom-out",
-      icon: "iD-icon-minus",
-      title: _t.append("zoom.out"),
-      action: zoomOut,
-      disabled: function() {
-        return !context.map().canZoomOut();
-      },
-      disabledTitle: _t.append("zoom.disabled.out"),
-      key: "-"
-    }];
-    function zoomIn(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomIn();
-    }
-    function zoomOut(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomOut();
-    }
-    function zoomInFurther(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomInFurther();
+  // modules/ui/photoviewer.js
+  function uiPhotoviewer(context) {
+    var dispatch14 = dispatch_default("resize");
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function photoviewer(selection2) {
+      selection2.append("button").attr("class", "thumb-hide").attr("title", _t("icons.close")).on("click", function() {
+        if (services.streetside) {
+          services.streetside.hideViewer(context);
+        }
+        if (services.mapillary) {
+          services.mapillary.hideViewer(context);
+        }
+        if (services.kartaview) {
+          services.kartaview.hideViewer(context);
+        }
+        if (services.mapilio) {
+          services.mapilio.hideViewer(context);
+        }
+        if (services.panoramax) {
+          services.panoramax.hideViewer(context);
+        }
+        if (services.vegbilder) {
+          services.vegbilder.hideViewer(context);
+        }
+      }).append("div").call(svgIcon("#iD-icon-close"));
+      function preventDefault(d3_event) {
+        d3_event.preventDefault();
+      }
+      selection2.append("button").attr("class", "resize-handle-xy").on("touchstart touchdown touchend", preventDefault).on(
+        _pointerPrefix + "down",
+        buildResizeListener(selection2, "resize", dispatch14, { resizeOnX: true, resizeOnY: true })
+      );
+      selection2.append("button").attr("class", "resize-handle-x").on("touchstart touchdown touchend", preventDefault).on(
+        _pointerPrefix + "down",
+        buildResizeListener(selection2, "resize", dispatch14, { resizeOnX: true })
+      );
+      selection2.append("button").attr("class", "resize-handle-y").on("touchstart touchdown touchend", preventDefault).on(
+        _pointerPrefix + "down",
+        buildResizeListener(selection2, "resize", dispatch14, { resizeOnY: true })
+      );
+      context.features().on("change.setPhotoFromViewer", function() {
+        setPhotoFromViewerButton();
+      });
+      context.history().on("change.setPhotoFromViewer", function() {
+        setPhotoFromViewerButton();
+      });
+      function setPhotoFromViewerButton() {
+        if (services.mapillary.isViewerOpen()) {
+          let setMapillaryPhotoId = function() {
+            const service = services.mapillary;
+            const image = service.getActiveImage();
+            const action = (graph) => context.selectedIDs().reduce((graph2, entityID) => {
+              const tags = graph2.entity(entityID).tags;
+              const action2 = actionChangeTags(entityID, { ...tags, mapillary: image.id });
+              return action2(graph2);
+            }, graph);
+            const annotation = _t("operations.change_tags.annotation");
+            context.perform(action, annotation);
+          };
+          if (context.mode().id !== "select" || !(layerStatus("mapillary") && getServiceId() === "mapillary")) {
+            buttonRemove();
+          } else {
+            if (selection2.select(".set-photo-from-viewer").empty()) {
+              const button = buttonCreate();
+              button.on("click", function(e3) {
+                e3.preventDefault();
+                e3.stopPropagation();
+                setMapillaryPhotoId();
+                buttonDisable("already_set");
+              });
+            }
+            buttonShowHide();
+          }
+        }
+        function layerStatus(which) {
+          const layers = context.layers();
+          const layer = layers.layer(which);
+          return layer.enabled();
+        }
+        function getServiceId() {
+          const hash = utilStringQs(window.location.hash);
+          let serviceId;
+          if (hash.photo) {
+            let result = hash.photo.split("/");
+            serviceId = result[0];
+          }
+          return serviceId;
+        }
+        function buttonCreate() {
+          const button = selection2.selectAll(".set-photo-from-viewer").data([0]);
+          const buttonEnter = button.enter().append("button").attr("class", "set-photo-from-viewer").call(svgIcon("#iD-icon-plus")).call(
+            uiTooltip().title(() => _t.append("inspector.set_photo_from_viewer")).placement("right")
+          );
+          buttonEnter.select(".tooltip").classed("dark", true).style("width", "300px");
+          return buttonEnter;
+        }
+        function buttonRemove() {
+          const button = selection2.selectAll(".set-photo-from-viewer").data([0]);
+          button.remove();
+        }
+        function buttonShowHide() {
+          const activeImage = services.mapillary.getActiveImage();
+          const graph = context.graph();
+          const entities = context.selectedIDs().map((id2) => graph.entity(id2));
+          if (entities.map((entity) => entity.tags.mapillary).every((value) => value === (activeImage == null ? void 0 : activeImage.id))) {
+            buttonDisable("already_set");
+          } else if (activeImage && entities.map((entity) => entity.extent().center()).every((loc) => geoSphericalDistance(loc, activeImage.loc) > 100)) {
+            buttonDisable("too_far");
+          } else {
+            buttonDisable(false);
+          }
+        }
+        function buttonDisable(reason) {
+          const disabled = reason !== false;
+          const button = selection2.selectAll(".set-photo-from-viewer").data([0]);
+          button.attr("disabled", disabled ? "true" : null);
+          button.classed("disabled", disabled);
+          button.call(uiTooltip().destroyAny);
+          if (disabled) {
+            button.call(
+              uiTooltip().title(() => _t.append("inspector.set_photo_from_viewer.disable.".concat(reason))).placement("right")
+            );
+          } else {
+            button.call(
+              uiTooltip().title(() => _t.append("inspector.set_photo_from_viewer.enable")).placement("right")
+            );
+          }
+          button.select(".tooltip").classed("dark", true).style("width", "300px");
+        }
+      }
+      function buildResizeListener(target, eventName, dispatch15, options2) {
+        var resizeOnX = !!options2.resizeOnX;
+        var resizeOnY = !!options2.resizeOnY;
+        var minHeight = options2.minHeight || 240;
+        var minWidth = options2.minWidth || 320;
+        var pointerId;
+        var startX;
+        var startY;
+        var startWidth;
+        var startHeight;
+        function startResize(d3_event) {
+          if (pointerId !== (d3_event.pointerId || "mouse")) return;
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          var mapSize = context.map().dimensions();
+          if (resizeOnX) {
+            var maxWidth = mapSize[0];
+            var newWidth = clamp3(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
+            target.style("width", newWidth + "px");
+          }
+          if (resizeOnY) {
+            var maxHeight = mapSize[1] - 90;
+            var newHeight = clamp3(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
+            target.style("height", newHeight + "px");
+          }
+          dispatch15.call(eventName, target, subtractPadding(utilGetDimensions(target, true), target));
+        }
+        function clamp3(num, min3, max3) {
+          return Math.max(min3, Math.min(num, max3));
+        }
+        function stopResize(d3_event) {
+          if (pointerId !== (d3_event.pointerId || "mouse")) return;
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          select_default2(window).on("." + eventName, null);
+        }
+        return function initResize(d3_event) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          pointerId = d3_event.pointerId || "mouse";
+          startX = d3_event.clientX;
+          startY = d3_event.clientY;
+          var targetRect = target.node().getBoundingClientRect();
+          startWidth = targetRect.width;
+          startHeight = targetRect.height;
+          select_default2(window).on(_pointerPrefix + "move." + eventName, startResize, false).on(_pointerPrefix + "up." + eventName, stopResize, false);
+          if (_pointerPrefix === "pointer") {
+            select_default2(window).on("pointercancel." + eventName, stopResize, false);
+          }
+        };
+      }
     }
-    function zoomOutFurther(d3_event) {
-      if (d3_event.shiftKey)
-        return;
-      d3_event.preventDefault();
-      context.map().zoomOutFurther();
+    photoviewer.onMapResize = function() {
+      var photoviewer2 = context.container().select(".photoviewer");
+      var content = context.container().select(".main-content");
+      var mapDimensions = utilGetDimensions(content, true);
+      var photoDimensions = utilGetDimensions(photoviewer2, true);
+      if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
+        var setPhotoDimensions = [
+          Math.min(photoDimensions[0], mapDimensions[0]),
+          Math.min(photoDimensions[1], mapDimensions[1] - 90)
+        ];
+        photoviewer2.style("width", setPhotoDimensions[0] + "px").style("height", setPhotoDimensions[1] + "px");
+        dispatch14.call("resize", photoviewer2, subtractPadding(setPhotoDimensions, photoviewer2));
+      }
+    };
+    function subtractPadding(dimensions, selection2) {
+      return [
+        dimensions[0] - parseFloat(selection2.style("padding-left")) - parseFloat(selection2.style("padding-right")),
+        dimensions[1] - parseFloat(selection2.style("padding-top")) - parseFloat(selection2.style("padding-bottom"))
+      ];
     }
+    return utilRebind(photoviewer, dispatch14, "on");
+  }
+
+  // modules/ui/restore.js
+  function uiRestore(context) {
     return function(selection2) {
-      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function(d) {
-        if (d.disabled()) {
-          return d.disabledTitle;
-        }
-        return d.title;
-      }).keys(function(d) {
-        return [d.key];
-      });
-      var lastPointerUpType;
-      var buttons = selection2.selectAll("button").data(zooms).enter().append("button").attr("class", function(d) {
-        return d.id;
-      }).on("pointerup.editor", function(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
-      }).on("click.editor", function(d3_event, d) {
-        if (!d.disabled()) {
-          d.action(d3_event);
-        } else if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
-          context.ui().flash.duration(2e3).iconName("#" + d.icon).iconClass("disabled").label(d.disabledTitle)();
-        }
-        lastPointerUpType = null;
-      }).call(tooltipBehavior);
-      buttons.each(function(d) {
-        select_default2(this).call(svgIcon("#" + d.icon, "light"));
-      });
-      utilKeybinding.plusKeys.forEach(function(key) {
-        context.keybinding().on([key], zoomIn);
-        context.keybinding().on([uiCmd("\u2325" + key)], zoomInFurther);
+      if (!context.history().hasRestorableChanges()) return;
+      let modalSelection = uiModal(selection2, true);
+      modalSelection.select(".modal").attr("class", "modal fillL");
+      let introModal = modalSelection.select(".content");
+      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("restore.heading"));
+      introModal.append("div").attr("class", "modal-section").append("p").call(_t.append("restore.description"));
+      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
+      let restore = buttonWrap.append("button").attr("class", "restore").on("click", () => {
+        context.history().restore();
+        modalSelection.remove();
       });
-      utilKeybinding.minusKeys.forEach(function(key) {
-        context.keybinding().on([key], zoomOut);
-        context.keybinding().on([uiCmd("\u2325" + key)], zoomOutFurther);
+      restore.append("svg").attr("class", "logo logo-restore").append("use").attr("xlink:href", "#iD-logo-restore");
+      restore.append("div").call(_t.append("restore.restore"));
+      let reset = buttonWrap.append("button").attr("class", "reset").on("click", () => {
+        context.history().clearSaved();
+        modalSelection.remove();
       });
-      function updateButtonStates() {
-        buttons.classed("disabled", function(d) {
-          return d.disabled();
-        }).each(function() {
-          var selection3 = select_default2(this);
-          if (!selection3.select(".tooltip.in").empty()) {
-            selection3.call(tooltipBehavior.updateContent);
-          }
-        });
+      reset.append("svg").attr("class", "logo logo-reset").append("use").attr("xlink:href", "#iD-logo-reset");
+      reset.append("div").call(_t.append("restore.reset"));
+      restore.node().focus();
+    };
+  }
+
+  // modules/ui/scale.js
+  function uiScale(context) {
+    var projection2 = context.projection, isImperial = !_mainLocalizer.usesMetric(), maxLength = 180, tickHeight = 8;
+    function scaleDefs(loc1, loc2) {
+      var lat = (loc2[1] + loc1[1]) / 2, conversion = isImperial ? 3.28084 : 1, dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion, scale = { dist: 0, px: 0, text: "" }, buckets, i3, val, dLon;
+      if (isImperial) {
+        buckets = [528e4, 528e3, 52800, 5280, 500, 50, 5, 1];
+      } else {
+        buckets = [5e6, 5e5, 5e4, 5e3, 500, 50, 5, 1];
       }
-      updateButtonStates();
-      context.map().on("move.uiZoom", updateButtonStates);
+      for (i3 = 0; i3 < buckets.length; i3++) {
+        val = buckets[i3];
+        if (dist >= val) {
+          scale.dist = Math.floor(dist / val) * val;
+          break;
+        } else {
+          scale.dist = +dist.toFixed(2);
+        }
+      }
+      dLon = geoMetersToLon(scale.dist / conversion, lat);
+      scale.px = Math.round(projection2([loc1[0] + dLon, loc1[1]])[0]);
+      scale.text = displayLength(scale.dist / conversion, isImperial);
+      return scale;
+    }
+    function update(selection2) {
+      var dims = context.map().dimensions(), loc1 = projection2.invert([0, dims[1]]), loc2 = projection2.invert([maxLength, dims[1]]), scale = scaleDefs(loc1, loc2);
+      selection2.select(".scale-path").attr("d", "M0.5,0.5v" + tickHeight + "h" + scale.px + "v-" + tickHeight);
+      selection2.select(".scale-text").style(_mainLocalizer.textDirection() === "ltr" ? "left" : "right", scale.px + 16 + "px").text(scale.text);
+    }
+    return function(selection2) {
+      function switchUnits() {
+        isImperial = !isImperial;
+        selection2.call(update);
+      }
+      var scalegroup = selection2.append("svg").attr("class", "scale").on("click", switchUnits).append("g").attr("transform", "translate(10,11)");
+      scalegroup.append("path").attr("class", "scale-path");
+      selection2.append("div").attr("class", "scale-text");
+      selection2.call(update);
+      context.map().on("move.scale", function() {
+        update(selection2);
+      });
     };
   }
 
-  // modules/ui/sections/raw_tag_editor.js
-  function uiSectionRawTagEditor(id2, context) {
-    var section = uiSection(id2, context).classes("raw-tag-editor").label(function() {
-      var count = Object.keys(_tags).filter(function(d) {
-        return d;
-      }).length;
-      return _t.append("inspector.title_count", { title: _t("inspector.tags"), count });
-    }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
-    var taginfo = services.taginfo;
-    var dispatch10 = dispatch_default("change");
-    var availableViews = [
-      { id: "list", icon: "#fas-th-list" },
-      { id: "text", icon: "#fas-i-cursor" }
-    ];
-    var _tagView = corePreferences("raw-tag-editor-view") || "list";
-    var _readOnlyTags = [];
-    var _orderedKeys = [];
-    var _showBlank = false;
-    var _pendingChange = null;
-    var _state;
-    var _presets;
-    var _tags;
-    var _entityIDs;
-    var _didInteract = false;
-    function interacted() {
-      _didInteract = true;
+  // modules/ui/shortcuts.js
+  function uiShortcuts(context) {
+    var detected = utilDetect();
+    var _activeTab = 0;
+    var _modalSelection;
+    var _selection = select_default2(null);
+    var _dataShortcuts;
+    function shortcutsModal(_modalSelection2) {
+      _modalSelection2.select(".modal").classed("modal-shortcuts", true);
+      var content = _modalSelection2.select(".content");
+      content.append("div").attr("class", "modal-section header").append("h2").call(_t.append("shortcuts.title"));
+      _mainFileFetcher.get("shortcuts").then(function(data) {
+        _dataShortcuts = data;
+        content.call(render);
+      }).catch(function() {
+      });
     }
-    function renderDisclosureContent(wrap2) {
-      _orderedKeys = _orderedKeys.filter(function(key) {
-        return _tags[key] !== void 0;
+    function render(selection2) {
+      if (!_dataShortcuts) return;
+      var wrapper = selection2.selectAll(".wrapper").data([0]);
+      var wrapperEnter = wrapper.enter().append("div").attr("class", "wrapper modal-section");
+      var tabsBar = wrapperEnter.append("div").attr("class", "tabs-bar");
+      var shortcutsList = wrapperEnter.append("div").attr("class", "shortcuts-list");
+      wrapper = wrapper.merge(wrapperEnter);
+      var tabs = tabsBar.selectAll(".tab").data(_dataShortcuts);
+      var tabsEnter = tabs.enter().append("a").attr("class", "tab").attr("href", "#").on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        var i3 = _dataShortcuts.indexOf(d2);
+        _activeTab = i3;
+        render(selection2);
       });
-      var all = Object.keys(_tags).sort();
-      var missingKeys = utilArrayDifference(all, _orderedKeys);
-      for (var i2 in missingKeys) {
-        _orderedKeys.push(missingKeys[i2]);
-      }
-      var rowData = _orderedKeys.map(function(key, i3) {
-        return { index: i3, key, value: _tags[key] };
+      tabsEnter.append("span").html(function(d2) {
+        return _t.html(d2.text);
       });
-      if (!rowData.length || _showBlank) {
-        _showBlank = false;
-        rowData.push({ index: rowData.length, key: "", value: "" });
-      }
-      var options2 = wrap2.selectAll(".raw-tag-options").data([0]);
-      options2.exit().remove();
-      var optionsEnter = options2.enter().insert("div", ":first-child").attr("class", "raw-tag-options").attr("role", "tablist");
-      var optionEnter = optionsEnter.selectAll(".raw-tag-option").data(availableViews, function(d) {
-        return d.id;
-      }).enter();
-      optionEnter.append("button").attr("class", function(d) {
-        return "raw-tag-option raw-tag-option-" + d.id + (_tagView === d.id ? " selected" : "");
-      }).attr("aria-selected", function(d) {
-        return _tagView === d.id;
-      }).attr("role", "tab").attr("title", function(d) {
-        return _t("icons." + d.id);
-      }).on("click", function(d3_event, d) {
-        _tagView = d.id;
-        corePreferences("raw-tag-editor-view", d.id);
-        wrap2.selectAll(".raw-tag-option").classed("selected", function(datum2) {
-          return datum2 === d;
-        }).attr("aria-selected", function(datum2) {
-          return datum2 === d;
-        });
-        wrap2.selectAll(".tag-text").classed("hide", d.id !== "text").each(setTextareaHeight);
-        wrap2.selectAll(".tag-list, .add-row").classed("hide", d.id !== "list");
-      }).each(function(d) {
-        select_default2(this).call(svgIcon(d.icon));
+      wrapper.selectAll(".tab").classed("active", function(d2, i3) {
+        return i3 === _activeTab;
       });
-      var textData = rowsToText(rowData);
-      var textarea = wrap2.selectAll(".tag-text").data([0]);
-      textarea = textarea.enter().append("textarea").attr("class", "tag-text" + (_tagView !== "text" ? " hide" : "")).call(utilNoAuto).attr("placeholder", _t("inspector.key_value")).attr("spellcheck", "false").merge(textarea);
-      textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on("input", setTextareaHeight).on("focus", interacted).on("blur", textChanged).on("change", textChanged);
-      var list = wrap2.selectAll(".tag-list").data([0]);
-      list = list.enter().append("ul").attr("class", "tag-list" + (_tagView !== "list" ? " hide" : "")).merge(list);
-      var addRowEnter = wrap2.selectAll(".add-row").data([0]).enter().append("div").attr("class", "add-row" + (_tagView !== "list" ? " hide" : ""));
-      addRowEnter.append("button").attr("class", "add-tag").attr("aria-label", _t("inspector.add_to_tag")).call(svgIcon("#iD-icon-plus", "light")).call(uiTooltip().title(() => _t.append("inspector.add_to_tag")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left")).on("click", addTag);
-      addRowEnter.append("div").attr("class", "space-value");
-      addRowEnter.append("div").attr("class", "space-buttons");
-      var items = list.selectAll(".tag-row").data(rowData, function(d) {
-        return d.key;
+      var shortcuts = shortcutsList.selectAll(".shortcut-tab").data(_dataShortcuts);
+      var shortcutsEnter = shortcuts.enter().append("div").attr("class", function(d2) {
+        return "shortcut-tab shortcut-tab-" + d2.tab;
       });
-      items.exit().each(unbind).remove();
-      var itemsEnter = items.enter().append("li").attr("class", "tag-row").classed("readonly", isReadOnly);
-      var innerWrap = itemsEnter.append("div").attr("class", "inner-wrap");
-      innerWrap.append("div").attr("class", "key-wrap").append("input").property("type", "text").attr("class", "key").call(utilNoAuto).on("focus", interacted).on("blur", keyChange).on("change", keyChange);
-      innerWrap.append("div").attr("class", "value-wrap").append("input").property("type", "text").attr("class", "value").call(utilNoAuto).on("focus", interacted).on("blur", valueChange).on("change", valueChange).on("keydown.push-more", pushMore);
-      innerWrap.append("button").attr("class", "form-field-button remove").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
-      items = items.merge(itemsEnter).sort(function(a, b) {
-        return a.index - b.index;
+      var columnsEnter = shortcutsEnter.selectAll(".shortcut-column").data(function(d2) {
+        return d2.columns;
+      }).enter().append("table").attr("class", "shortcut-column");
+      var rowsEnter = columnsEnter.selectAll(".shortcut-row").data(function(d2) {
+        return d2.rows;
+      }).enter().append("tr").attr("class", "shortcut-row");
+      var sectionRows = rowsEnter.filter(function(d2) {
+        return !d2.shortcuts;
       });
-      items.each(function(d) {
-        var row = select_default2(this);
-        var key = row.select("input.key");
-        var value = row.select("input.value");
-        if (_entityIDs && taginfo && _state !== "hover") {
-          bindTypeahead(key, value);
-        }
-        var referenceOptions = { key: d.key };
-        if (typeof d.value === "string") {
-          referenceOptions.value = d.value;
-        }
-        var reference = uiTagReference(referenceOptions, context);
-        if (_state === "hover") {
-          reference.showing(false);
+      sectionRows.append("td");
+      sectionRows.append("td").attr("class", "shortcut-section").append("h3").html(function(d2) {
+        return _t.html(d2.text);
+      });
+      var shortcutRows = rowsEnter.filter(function(d2) {
+        return d2.shortcuts;
+      });
+      var shortcutKeys = shortcutRows.append("td").attr("class", "shortcut-keys");
+      var modifierKeys = shortcutKeys.filter(function(d2) {
+        return d2.modifiers;
+      });
+      modifierKeys.selectAll("kbd.modifier").data(function(d2) {
+        if (detected.os === "win" && d2.text === "shortcuts.editing.commands.redo") {
+          return ["\u2318"];
+        } else if (detected.os !== "mac" && d2.text === "shortcuts.browsing.display_options.fullscreen") {
+          return [];
+        } else {
+          return d2.modifiers;
         }
-        row.select(".inner-wrap").call(reference.button);
-        row.call(reference.body);
-        row.select("button.remove");
+      }).enter().each(function() {
+        var selection3 = select_default2(this);
+        selection3.append("kbd").attr("class", "modifier").text(function(d2) {
+          return uiCmd.display(d2);
+        });
+        selection3.append("span").text("+");
       });
-      items.selectAll("input.key").attr("title", function(d) {
-        return d.key;
-      }).call(utilGetSetValue, function(d) {
-        return d.key;
-      }).attr("readonly", function(d) {
-        return isReadOnly(d) || null;
-      });
-      items.selectAll("input.value").attr("title", function(d) {
-        return Array.isArray(d.value) ? d.value.filter(Boolean).join("\n") : d.value;
-      }).classed("mixed", function(d) {
-        return Array.isArray(d.value);
-      }).attr("placeholder", function(d) {
-        return typeof d.value === "string" ? null : _t("inspector.multiple_values");
-      }).call(utilGetSetValue, function(d) {
-        return typeof d.value === "string" ? d.value : "";
-      }).attr("readonly", function(d) {
-        return isReadOnly(d) || null;
-      });
-      items.selectAll("button.remove").on(("PointerEvent" in window ? "pointer" : "mouse") + "down", removeTag);
-    }
-    function isReadOnly(d) {
-      for (var i2 = 0; i2 < _readOnlyTags.length; i2++) {
-        if (d.key.match(_readOnlyTags[i2]) !== null) {
-          return true;
+      shortcutKeys.selectAll("kbd.shortcut").data(function(d2) {
+        var arr = d2.shortcuts;
+        if (detected.os === "win" && d2.text === "shortcuts.editing.commands.redo") {
+          arr = ["Y"];
+        } else if (detected.os !== "mac" && d2.text === "shortcuts.browsing.display_options.fullscreen") {
+          arr = ["F11"];
         }
-      }
-      return false;
-    }
-    function setTextareaHeight() {
-      if (_tagView !== "text")
-        return;
-      var selection2 = select_default2(this);
-      var matches = selection2.node().value.match(/\n/g);
-      var lineCount = 2 + Number(matches && matches.length);
-      var lineHeight = 20;
-      selection2.style("height", lineCount * lineHeight + "px");
-    }
-    function stringify3(s) {
-      return JSON.stringify(s).slice(1, -1);
-    }
-    function unstringify(s) {
-      var leading = "";
-      var trailing = "";
-      if (s.length < 1 || s.charAt(0) !== '"') {
-        leading = '"';
-      }
-      if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === "\\") {
-        trailing = '"';
-      }
-      return JSON.parse(leading + s + trailing);
-    }
-    function rowsToText(rows) {
-      var str2 = rows.filter(function(row) {
-        return row.key && row.key.trim() !== "";
-      }).map(function(row) {
-        var rawVal = row.value;
-        if (typeof rawVal !== "string")
-          rawVal = "*";
-        var val = rawVal ? stringify3(rawVal) : "";
-        return stringify3(row.key) + "=" + val;
-      }).join("\n");
-      if (_state !== "hover" && str2.length) {
-        return str2 + "\n";
-      }
-      return str2;
-    }
-    function textChanged() {
-      var newText = this.value.trim();
-      var newTags = {};
-      newText.split("\n").forEach(function(row) {
-        var m = row.match(/^\s*([^=]+)=(.*)$/);
-        if (m !== null) {
-          var k = context.cleanTagKey(unstringify(m[1].trim()));
-          var v = context.cleanTagValue(unstringify(m[2].trim()));
-          newTags[k] = v;
+        arr = arr.map(function(s2) {
+          return uiCmd.display(s2.indexOf(".") !== -1 ? _t(s2) : s2);
+        });
+        return utilArrayUniq(arr).map(function(s2) {
+          return {
+            shortcut: s2,
+            separator: d2.separator,
+            suffix: d2.suffix
+          };
+        });
+      }).enter().each(function(d2, i3, nodes) {
+        var selection3 = select_default2(this);
+        var click = d2.shortcut.toLowerCase().match(/(.*).click/);
+        if (click && click[1]) {
+          selection3.call(svgIcon("#iD-walkthrough-mouse-" + click[1], "operation"));
+        } else if (d2.shortcut.toLowerCase() === "long-press") {
+          selection3.call(svgIcon("#iD-walkthrough-longpress", "longpress operation"));
+        } else if (d2.shortcut.toLowerCase() === "tap") {
+          selection3.call(svgIcon("#iD-walkthrough-tap", "tap operation"));
+        } else {
+          selection3.append("kbd").attr("class", "shortcut").text(function(d4) {
+            return d4.shortcut;
+          });
         }
-      });
-      var tagDiff = utilTagDiff(_tags, newTags);
-      if (!tagDiff.length)
-        return;
-      _pendingChange = _pendingChange || {};
-      tagDiff.forEach(function(change) {
-        if (isReadOnly({ key: change.key }))
-          return;
-        if (change.newVal === "*" && typeof change.oldVal !== "string")
-          return;
-        if (change.type === "-") {
-          _pendingChange[change.key] = void 0;
-        } else if (change.type === "+") {
-          _pendingChange[change.key] = change.newVal || "";
+        if (i3 < nodes.length - 1) {
+          selection3.append("span").html(d2.separator || "\xA0" + _t.html("shortcuts.or") + "\xA0");
+        } else if (i3 === nodes.length - 1 && d2.suffix) {
+          selection3.append("span").text(d2.suffix);
         }
       });
-      if (Object.keys(_pendingChange).length === 0) {
-        _pendingChange = null;
-        return;
-      }
-      scheduleChange();
-    }
-    function pushMore(d3_event) {
-      if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll(".tag-list li:last-child input.value").node() === this && utilGetSetValue(select_default2(this))) {
-        addTag();
-      }
-    }
-    function bindTypeahead(key, value) {
-      if (isReadOnly(key.datum()))
-        return;
-      if (Array.isArray(value.datum().value)) {
-        value.call(uiCombobox(context, "tag-value").minItems(1).fetcher(function(value2, callback) {
-          var keyString = utilGetSetValue(key);
-          if (!_tags[keyString])
-            return;
-          var data = _tags[keyString].filter(Boolean).map(function(tagValue) {
-            return {
-              value: tagValue,
-              title: tagValue
-            };
-          });
-          callback(data);
-        }));
-        return;
-      }
-      var geometry = context.graph().geometry(_entityIDs[0]);
-      key.call(uiCombobox(context, "tag-key").fetcher(function(value2, callback) {
-        taginfo.keys({
-          debounce: true,
-          geometry,
-          query: value2
-        }, function(err, data) {
-          if (!err) {
-            var filtered = data.filter(function(d) {
-              return _tags[d.value] === void 0;
-            });
-            callback(sort(value2, filtered));
-          }
-        });
-      }));
-      value.call(uiCombobox(context, "tag-value").fetcher(function(value2, callback) {
-        taginfo.values({
-          debounce: true,
-          key: utilGetSetValue(key),
-          geometry,
-          query: value2
-        }, function(err, data) {
-          if (!err)
-            callback(sort(value2, data));
+      shortcutKeys.filter(function(d2) {
+        return d2.gesture;
+      }).each(function() {
+        var selection3 = select_default2(this);
+        selection3.append("span").text("+");
+        selection3.append("span").attr("class", "gesture").html(function(d2) {
+          return _t.html(d2.gesture);
         });
-      }));
-      function sort(value2, data) {
-        var sameletter = [];
-        var other = [];
-        for (var i2 = 0; i2 < data.length; i2++) {
-          if (data[i2].value.substring(0, value2.length) === value2) {
-            sameletter.push(data[i2]);
+      });
+      shortcutRows.append("td").attr("class", "shortcut-desc").html(function(d2) {
+        return d2.text ? _t.html(d2.text) : "\xA0";
+      });
+      wrapper.selectAll(".shortcut-tab").style("display", function(d2, i3) {
+        return i3 === _activeTab ? "flex" : "none";
+      });
+    }
+    return function(selection2, show) {
+      _selection = selection2;
+      if (show) {
+        _modalSelection = uiModal(selection2);
+        _modalSelection.call(shortcutsModal);
+      } else {
+        context.keybinding().on([_t("shortcuts.toggle.key"), "?"], function() {
+          if (context.container().selectAll(".modal-shortcuts").size()) {
+            if (_modalSelection) {
+              _modalSelection.close();
+              _modalSelection = null;
+            }
           } else {
-            other.push(data[i2]);
+            _modalSelection = uiModal(_selection);
+            _modalSelection.call(shortcutsModal);
           }
-        }
-        return sameletter.concat(other);
+        });
       }
-    }
-    function unbind() {
-      var row = select_default2(this);
-      row.selectAll("input.key").call(uiCombobox.off, context);
-      row.selectAll("input.value").call(uiCombobox.off, context);
-    }
-    function keyChange(d3_event, d) {
-      if (select_default2(this).attr("readonly"))
+    };
+  }
+
+  // modules/ui/data_header.js
+  function uiDataHeader() {
+    var _datum;
+    function dataHeader(selection2) {
+      var header = selection2.selectAll(".data-header").data(
+        _datum ? [_datum] : [],
+        function(d2) {
+          return d2.__featurehash__;
+        }
+      );
+      header.exit().remove();
+      var headerEnter = header.enter().append("div").attr("class", "data-header");
+      var iconEnter = headerEnter.append("div").attr("class", "data-header-icon");
+      iconEnter.append("div").attr("class", "preset-icon-28").call(svgIcon("#iD-icon-data", "note-fill"));
+      headerEnter.append("div").attr("class", "data-header-label").call(_t.append("map_data.layers.custom.title"));
+    }
+    dataHeader.datum = function(val) {
+      if (!arguments.length) return _datum;
+      _datum = val;
+      return this;
+    };
+    return dataHeader;
+  }
+
+  // modules/ui/disclosure.js
+  function uiDisclosure(context, key, expandedDefault) {
+    var dispatch14 = dispatch_default("toggled");
+    var _expanded;
+    var _label = utilFunctor("");
+    var _updatePreference = true;
+    var _content = function() {
+    };
+    var disclosure = function(selection2) {
+      if (_expanded === void 0 || _expanded === null) {
+        var preference = corePreferences("disclosure." + key + ".expanded");
+        _expanded = preference === null ? !!expandedDefault : preference === "true";
+      }
+      var hideToggle = selection2.selectAll(".hide-toggle-" + key).data([0]);
+      var hideToggleEnter = hideToggle.enter().append("h3").append("a").attr("role", "button").attr("href", "#").attr("class", "hide-toggle hide-toggle-" + key).call(svgIcon("", "pre-text", "hide-toggle-icon"));
+      hideToggleEnter.append("span").attr("class", "hide-toggle-text");
+      hideToggle = hideToggleEnter.merge(hideToggle);
+      hideToggle.on("click", toggle).attr("title", _t("icons.".concat(_expanded ? "collapse" : "expand"))).attr("aria-expanded", _expanded).classed("expanded", _expanded);
+      const label = _label();
+      const labelSelection = hideToggle.selectAll(".hide-toggle-text");
+      if (typeof label !== "function") {
+        labelSelection.text(_label());
+      } else {
+        labelSelection.text("").call(label);
+      }
+      hideToggle.selectAll(".hide-toggle-icon").attr(
+        "xlink:href",
+        _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
+      );
+      var wrap2 = selection2.selectAll(".disclosure-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "disclosure-wrap disclosure-wrap-" + key).merge(wrap2).classed("hide", !_expanded);
+      if (_expanded) {
+        wrap2.call(_content);
+      }
+      function toggle(d3_event) {
+        d3_event.preventDefault();
+        _expanded = !_expanded;
+        if (_updatePreference) {
+          corePreferences("disclosure." + key + ".expanded", _expanded);
+        }
+        hideToggle.classed("expanded", _expanded).attr("aria-expanded", _expanded).attr("title", _t("icons.".concat(_expanded ? "collapse" : "expand")));
+        hideToggle.selectAll(".hide-toggle-icon").attr(
+          "xlink:href",
+          _expanded ? "#iD-icon-down" : _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward"
+        );
+        wrap2.call(uiToggle(_expanded));
+        if (_expanded) {
+          wrap2.call(_content);
+        }
+        dispatch14.call("toggled", this, _expanded);
+      }
+    };
+    disclosure.label = function(val) {
+      if (!arguments.length) return _label;
+      _label = utilFunctor(val);
+      return disclosure;
+    };
+    disclosure.expanded = function(val) {
+      if (!arguments.length) return _expanded;
+      _expanded = val;
+      return disclosure;
+    };
+    disclosure.updatePreference = function(val) {
+      if (!arguments.length) return _updatePreference;
+      _updatePreference = val;
+      return disclosure;
+    };
+    disclosure.content = function(val) {
+      if (!arguments.length) return _content;
+      _content = val;
+      return disclosure;
+    };
+    return utilRebind(disclosure, dispatch14, "on");
+  }
+
+  // modules/ui/section.js
+  function uiSection(id2, context) {
+    var _classes = utilFunctor("");
+    var _shouldDisplay;
+    var _content;
+    var _disclosure;
+    var _label;
+    var _expandedByDefault = utilFunctor(true);
+    var _disclosureContent;
+    var _disclosureExpanded;
+    var _containerSelection = select_default2(null);
+    var section = {
+      id: id2
+    };
+    section.classes = function(val) {
+      if (!arguments.length) return _classes;
+      _classes = utilFunctor(val);
+      return section;
+    };
+    section.label = function(val) {
+      if (!arguments.length) return _label;
+      _label = utilFunctor(val);
+      return section;
+    };
+    section.expandedByDefault = function(val) {
+      if (!arguments.length) return _expandedByDefault;
+      _expandedByDefault = utilFunctor(val);
+      return section;
+    };
+    section.shouldDisplay = function(val) {
+      if (!arguments.length) return _shouldDisplay;
+      _shouldDisplay = utilFunctor(val);
+      return section;
+    };
+    section.content = function(val) {
+      if (!arguments.length) return _content;
+      _content = val;
+      return section;
+    };
+    section.disclosureContent = function(val) {
+      if (!arguments.length) return _disclosureContent;
+      _disclosureContent = val;
+      return section;
+    };
+    section.disclosureExpanded = function(val) {
+      if (!arguments.length) return _disclosureExpanded;
+      _disclosureExpanded = val;
+      return section;
+    };
+    section.render = function(selection2) {
+      _containerSelection = selection2.selectAll(".section-" + id2).data([0]);
+      var sectionEnter = _containerSelection.enter().append("div").attr("class", "section section-" + id2 + " " + (_classes && _classes() || ""));
+      _containerSelection = sectionEnter.merge(_containerSelection);
+      _containerSelection.call(renderContent);
+    };
+    section.reRender = function() {
+      _containerSelection.call(renderContent);
+    };
+    section.selection = function() {
+      return _containerSelection;
+    };
+    section.disclosure = function() {
+      return _disclosure;
+    };
+    function renderContent(selection2) {
+      if (_shouldDisplay) {
+        var shouldDisplay = _shouldDisplay();
+        selection2.classed("hide", !shouldDisplay);
+        if (!shouldDisplay) {
+          selection2.html("");
+          return;
+        }
+      }
+      if (_disclosureContent) {
+        if (!_disclosure) {
+          _disclosure = uiDisclosure(context, id2.replace(/-/g, "_"), _expandedByDefault()).label(_label || "").content(_disclosureContent);
+        }
+        if (_disclosureExpanded !== void 0) {
+          _disclosure.expanded(_disclosureExpanded);
+          _disclosureExpanded = void 0;
+        }
+        selection2.call(_disclosure);
+        return;
+      }
+      if (_content) {
+        selection2.call(_content);
+      }
+    }
+    return section;
+  }
+
+  // modules/ui/tag_reference.js
+  function uiTagReference(what) {
+    var wikibase = what.qid ? services.wikidata : services.osmWikibase;
+    var tagReference = {};
+    var _button = select_default2(null);
+    var _body = select_default2(null);
+    var _loaded;
+    var _showing;
+    function load() {
+      if (!wikibase) return;
+      _button.classed("tag-reference-loading", true);
+      wikibase.getDocs(what, gotDocs);
+    }
+    function gotDocs(err, docs) {
+      _body.html("");
+      if (!docs || !docs.title) {
+        _body.append("p").attr("class", "tag-reference-description").call(_t.append("inspector.no_documentation_key"));
+        done();
+        return;
+      }
+      if (docs.imageURL) {
+        _body.append("img").attr("class", "tag-reference-wiki-image").attr("alt", docs.description).attr("src", docs.imageURL).on("load", function() {
+          done();
+        }).on("error", function() {
+          select_default2(this).remove();
+          done();
+        });
+      } else {
+        done();
+      }
+      var tagReferenceDescription = _body.append("p").attr("class", "tag-reference-description").append("span");
+      if (docs.description) {
+        tagReferenceDescription = tagReferenceDescription.attr("class", "localized-text").attr("lang", docs.descriptionLocaleCode || "und").text(docs.description);
+      } else {
+        tagReferenceDescription = tagReferenceDescription.call(_t.append("inspector.no_documentation_key"));
+      }
+      tagReferenceDescription.append("a").attr("class", "tag-reference-edit").attr("target", "_blank").attr("title", _t("inspector.edit_reference")).attr("href", docs.editURL).call(svgIcon("#iD-icon-edit", "inline"));
+      if (docs.wiki) {
+        _body.append("a").attr("class", "tag-reference-link").attr("target", "_blank").attr("href", docs.wiki.url).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append(docs.wiki.text));
+      }
+      if (what.key === "comment") {
+        _body.append("a").attr("class", "tag-reference-comment-link").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", _t("commit.about_changeset_comments_link")).append("span").call(_t.append("commit.about_changeset_comments"));
+      }
+    }
+    function done() {
+      _loaded = true;
+      _button.classed("tag-reference-loading", false);
+      _body.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1");
+      _showing = true;
+      _button.selectAll("svg.icon use").each(function() {
+        var iconUse = select_default2(this);
+        if (iconUse.attr("href") === "#iD-icon-info") {
+          iconUse.attr("href", "#iD-icon-info-filled");
+        }
+      });
+    }
+    function hide() {
+      _body.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
+        _body.classed("expanded", false);
+      });
+      _showing = false;
+      _button.selectAll("svg.icon use").each(function() {
+        var iconUse = select_default2(this);
+        if (iconUse.attr("href") === "#iD-icon-info-filled") {
+          iconUse.attr("href", "#iD-icon-info");
+        }
+      });
+    }
+    tagReference.button = function(selection2, klass, iconName) {
+      _button = selection2.selectAll(".tag-reference-button").data([0]);
+      _button = _button.enter().append("button").attr("class", "tag-reference-button " + (klass || "")).attr("title", _t("icons.information")).call(svgIcon("#iD-icon-" + (iconName || "inspect"))).merge(_button);
+      _button.on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
+        this.blur();
+        if (_showing) {
+          hide();
+        } else if (_loaded) {
+          done();
+        } else {
+          load();
+        }
+      });
+    };
+    tagReference.body = function(selection2) {
+      var itemID = what.qid || what.key + "-" + (what.value || "");
+      _body = selection2.selectAll(".tag-reference-body").data([itemID], function(d2) {
+        return d2;
+      });
+      _body.exit().remove();
+      _body = _body.enter().append("div").attr("class", "tag-reference-body").style("max-height", "0").style("opacity", "0").merge(_body);
+      if (_showing === false) {
+        hide();
+      }
+    };
+    tagReference.showing = function(val) {
+      if (!arguments.length) return _showing;
+      _showing = val;
+      return tagReference;
+    };
+    return tagReference;
+  }
+
+  // modules/ui/sections/raw_tag_editor.js
+  function uiSectionRawTagEditor(id2, context) {
+    var section = uiSection(id2, context).classes("raw-tag-editor").label(function() {
+      var count = Object.keys(_tags).filter(function(d2) {
+        return d2;
+      }).length;
+      return _t.append("inspector.title_count", { title: _t("inspector.tags"), count });
+    }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
+    var taginfo = services.taginfo;
+    var dispatch14 = dispatch_default("change");
+    var availableViews = [
+      { id: "list", icon: "#fas-th-list" },
+      { id: "text", icon: "#fas-i-cursor" }
+    ];
+    let _discardTags = {};
+    _mainFileFetcher.get("discarded").then((d2) => {
+      _discardTags = d2;
+    }).catch(() => {
+    });
+    var _tagView = corePreferences("raw-tag-editor-view") || "list";
+    var _readOnlyTags = [];
+    var _orderedKeys = [];
+    var _showBlank = false;
+    var _pendingChange = null;
+    var _state;
+    var _presets;
+    var _tags;
+    var _entityIDs;
+    var _didInteract = false;
+    function interacted() {
+      _didInteract = true;
+    }
+    function renderDisclosureContent(wrap2) {
+      _orderedKeys = _orderedKeys.filter(function(key) {
+        return _tags[key] !== void 0;
+      });
+      var all = Object.keys(_tags).sort();
+      var missingKeys = utilArrayDifference(all, _orderedKeys);
+      for (var i3 in missingKeys) {
+        _orderedKeys.push(missingKeys[i3]);
+      }
+      var rowData = _orderedKeys.map(function(key, i4) {
+        return { index: i4, key, value: _tags[key] };
+      });
+      if (!rowData.length || _showBlank) {
+        _showBlank = false;
+        rowData.push({ index: rowData.length, key: "", value: "" });
+      }
+      var options2 = wrap2.selectAll(".raw-tag-options").data([0]);
+      options2.exit().remove();
+      var optionsEnter = options2.enter().insert("div", ":first-child").attr("class", "raw-tag-options").attr("role", "tablist");
+      var optionEnter = optionsEnter.selectAll(".raw-tag-option").data(availableViews, function(d2) {
+        return d2.id;
+      }).enter();
+      optionEnter.append("button").attr("class", function(d2) {
+        return "raw-tag-option raw-tag-option-" + d2.id + (_tagView === d2.id ? " selected" : "");
+      }).attr("aria-selected", function(d2) {
+        return _tagView === d2.id;
+      }).attr("role", "tab").attr("title", function(d2) {
+        return _t("icons." + d2.id);
+      }).on("click", function(d3_event, d2) {
+        _tagView = d2.id;
+        corePreferences("raw-tag-editor-view", d2.id);
+        wrap2.selectAll(".raw-tag-option").classed("selected", function(datum2) {
+          return datum2 === d2;
+        }).attr("aria-selected", function(datum2) {
+          return datum2 === d2;
+        });
+        wrap2.selectAll(".tag-text").classed("hide", d2.id !== "text").each(setTextareaHeight);
+        wrap2.selectAll(".tag-list, .add-row").classed("hide", d2.id !== "list");
+      }).each(function(d2) {
+        select_default2(this).call(svgIcon(d2.icon));
+      });
+      var textData = rowsToText(rowData);
+      var textarea = wrap2.selectAll(".tag-text").data([0]);
+      textarea = textarea.enter().append("textarea").attr("class", "tag-text" + (_tagView !== "text" ? " hide" : "")).call(utilNoAuto).attr("placeholder", _t("inspector.key_value")).attr("spellcheck", "false").merge(textarea);
+      textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on("input", setTextareaHeight).on("focus", interacted).on("blur", textChanged).on("change", textChanged);
+      var list2 = wrap2.selectAll(".tag-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "tag-list" + (_tagView !== "list" ? " hide" : "")).merge(list2);
+      var addRowEnter = wrap2.selectAll(".add-row").data([0]).enter().append("div").attr("class", "add-row" + (_tagView !== "list" ? " hide" : ""));
+      addRowEnter.append("button").attr("class", "add-tag").attr("aria-label", _t("inspector.add_to_tag")).call(svgIcon("#iD-icon-plus", "light")).call(uiTooltip().title(() => _t.append("inspector.add_to_tag")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left")).on("click", addTag);
+      addRowEnter.append("div").attr("class", "space-value");
+      addRowEnter.append("div").attr("class", "space-buttons");
+      var items = list2.selectAll(".tag-row").data(rowData, function(d2) {
+        return d2.key;
+      });
+      items.exit().each(unbind).remove();
+      var itemsEnter = items.enter().append("li").attr("class", "tag-row").classed("readonly", isReadOnly);
+      var innerWrap = itemsEnter.append("div").attr("class", "inner-wrap");
+      innerWrap.append("div").attr("class", "key-wrap").append("input").property("type", "text").attr("class", "key").call(utilNoAuto).on("focus", interacted).on("blur", keyChange).on("change", keyChange);
+      innerWrap.append("div").attr("class", "value-wrap").append("input").property("type", "text").attr("class", "value").call(utilNoAuto).on("focus", interacted).on("blur", valueChange).on("change", valueChange).on("keydown.push-more", pushMore);
+      innerWrap.append("button").attr("class", "form-field-button remove").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
+      items = items.merge(itemsEnter).sort(function(a2, b2) {
+        return a2.index - b2.index;
+      });
+      items.each(function(d2) {
+        var row = select_default2(this);
+        var key = row.select("input.key");
+        var value = row.select("input.value");
+        if (_entityIDs && taginfo && _state !== "hover") {
+          bindTypeahead(key, value);
+        }
+        var referenceOptions = { key: d2.key };
+        if (typeof d2.value === "string") {
+          referenceOptions.value = d2.value;
+        }
+        var reference = uiTagReference(referenceOptions, context);
+        if (_state === "hover") {
+          reference.showing(false);
+        }
+        row.select(".inner-wrap").call(reference.button);
+        row.call(reference.body);
+        row.select("button.remove");
+      });
+      items.selectAll("input.key").attr("title", function(d2) {
+        return d2.key;
+      }).call(utilGetSetValue, function(d2) {
+        return d2.key;
+      }).attr("readonly", function(d2) {
+        return isReadOnly(d2) || null;
+      });
+      items.selectAll("input.value").attr("title", function(d2) {
+        return Array.isArray(d2.value) ? d2.value.filter(Boolean).join("\n") : d2.value;
+      }).classed("mixed", function(d2) {
+        return Array.isArray(d2.value);
+      }).attr("placeholder", function(d2) {
+        return typeof d2.value === "string" ? null : _t("inspector.multiple_values");
+      }).call(utilGetSetValue, function(d2) {
+        return typeof d2.value === "string" ? d2.value : "";
+      }).attr("readonly", function(d2) {
+        return isReadOnly(d2) || null;
+      });
+      items.selectAll("button.remove").on(
+        ("PointerEvent" in window ? "pointer" : "mouse") + "down",
+        // 'click' fires too late - #5878
+        (d3_event, d2) => {
+          if (d3_event.button !== 0) return;
+          removeTag(d3_event, d2);
+        }
+      );
+    }
+    function isReadOnly(d2) {
+      for (var i3 = 0; i3 < _readOnlyTags.length; i3++) {
+        if (d2.key.match(_readOnlyTags[i3]) !== null) {
+          return true;
+        }
+      }
+      return false;
+    }
+    function setTextareaHeight() {
+      if (_tagView !== "text") return;
+      var selection2 = select_default2(this);
+      var matches = selection2.node().value.match(/\n/g);
+      var lineCount = 2 + Number(matches && matches.length);
+      var lineHeight = 20;
+      selection2.style("height", lineCount * lineHeight + "px");
+    }
+    function stringify3(s2) {
+      const stringified = JSON.stringify(s2).slice(1, -1);
+      if (stringified !== s2) {
+        return '"'.concat(stringified, '"');
+      } else {
+        return s2;
+      }
+    }
+    function unstringify(s2) {
+      const isQuoted = s2.length > 1 && s2.charAt(0) === '"' && s2.charAt(s2.length - 1) === '"';
+      if (isQuoted) {
+        try {
+          return JSON.parse(s2);
+        } catch {
+          return s2;
+        }
+      } else {
+        return s2;
+      }
+    }
+    function rowsToText(rows) {
+      var str = rows.filter(function(row) {
+        return row.key && row.key.trim() !== "";
+      }).map(function(row) {
+        var rawVal = row.value;
+        if (typeof rawVal !== "string") rawVal = "*";
+        var val = rawVal ? stringify3(rawVal) : "";
+        return stringify3(row.key) + "=" + val;
+      }).join("\n");
+      if (_state !== "hover" && str.length) {
+        return str + "\n";
+      }
+      return str;
+    }
+    function textChanged() {
+      var newText = this.value.trim();
+      var newTags = {};
+      newText.split("\n").forEach(function(row) {
+        var m2 = row.match(/^\s*([^=]+)=(.*)$/);
+        if (m2 !== null) {
+          var k2 = context.cleanTagKey(unstringify(m2[1].trim()));
+          var v2 = context.cleanTagValue(unstringify(m2[2].trim()));
+          newTags[k2] = v2;
+        }
+      });
+      var tagDiff = utilTagDiff(_tags, newTags);
+      if (!tagDiff.length) return;
+      _pendingChange = _pendingChange || {};
+      tagDiff.forEach(function(change) {
+        if (isReadOnly({ key: change.key })) return;
+        if (change.newVal === "*" && typeof change.oldVal !== "string") return;
+        if (change.type === "-") {
+          _pendingChange[change.key] = void 0;
+        } else if (change.type === "+") {
+          _pendingChange[change.key] = change.newVal || "";
+        }
+      });
+      if (Object.keys(_pendingChange).length === 0) {
+        _pendingChange = null;
         return;
-      var kOld = d.key;
-      if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === void 0)
+      }
+      scheduleChange();
+    }
+    function pushMore(d3_event) {
+      if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll(".tag-list li:last-child input.value").node() === this && utilGetSetValue(select_default2(this))) {
+        addTag();
+      }
+    }
+    function bindTypeahead(key, value) {
+      if (isReadOnly(key.datum())) return;
+      if (Array.isArray(value.datum().value)) {
+        value.call(uiCombobox(context, "tag-value").minItems(1).fetcher(function(value2, callback) {
+          var keyString = utilGetSetValue(key);
+          if (!_tags[keyString]) return;
+          var data = _tags[keyString].map(function(tagValue) {
+            if (!tagValue) {
+              return {
+                value: " ",
+                title: _t("inspector.empty"),
+                display: (selection2) => selection2.text("").classed("virtual-option", true).call(_t.append("inspector.empty"))
+              };
+            }
+            return {
+              value: tagValue,
+              title: tagValue
+            };
+          });
+          callback(data);
+        }));
         return;
+      }
+      var geometry = context.graph().geometry(_entityIDs[0]);
+      key.call(uiCombobox(context, "tag-key").fetcher(function(value2, callback) {
+        taginfo.keys({
+          debounce: true,
+          geometry,
+          query: value2
+        }, function(err, data) {
+          if (!err) {
+            const filtered = data.filter((d2) => _tags[d2.value] === void 0).filter((d2) => !(d2.value in _discardTags)).filter((d2) => !/_\d$/.test(d2)).filter((d2) => d2.value.toLowerCase().includes(value2.toLowerCase()));
+            callback(sort(value2, filtered));
+          }
+        });
+      }));
+      value.call(uiCombobox(context, "tag-value").fetcher(function(value2, callback) {
+        taginfo.values({
+          debounce: true,
+          key: utilGetSetValue(key),
+          geometry,
+          query: value2
+        }, function(err, data) {
+          if (!err) {
+            const filtered = data.filter((d2) => d2.value.toLowerCase().includes(value2.toLowerCase()));
+            callback(sort(value2, filtered));
+          }
+        });
+      }).caseSensitive(allowUpperCaseTagValues.test(utilGetSetValue(key))));
+      function sort(value2, data) {
+        var sameletter = [];
+        var other = [];
+        for (var i3 = 0; i3 < data.length; i3++) {
+          if (data[i3].value.substring(0, value2.length) === value2) {
+            sameletter.push(data[i3]);
+          } else {
+            other.push(data[i3]);
+          }
+        }
+        return sameletter.concat(other);
+      }
+    }
+    function unbind() {
+      var row = select_default2(this);
+      row.selectAll("input.key").call(uiCombobox.off, context);
+      row.selectAll("input.value").call(uiCombobox.off, context);
+    }
+    function keyChange(d3_event, d2) {
+      if (select_default2(this).attr("readonly")) return;
+      var kOld = d2.key;
+      if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === void 0) return;
       var kNew = context.cleanTagKey(this.value.trim());
       if (isReadOnly({ key: kNew })) {
         this.value = kOld;
@@ -65524,8 +64745,8 @@ ${content}</tr>
       }
       if (kNew && kNew !== kOld && _tags[kNew] !== void 0) {
         this.value = kOld;
-        section.selection().selectAll(".tag-list input.value").each(function(d2) {
-          if (d2.key === kNew) {
+        section.selection().selectAll(".tag-list input.value").each(function(d4) {
+          if (d4.key === kNew) {
             var input = select_default2(this).node();
             input.focus();
             input.select();
@@ -65535,8 +64756,7 @@ ${content}</tr>
       }
       _pendingChange = _pendingChange || {};
       if (kOld) {
-        if (kOld === kNew)
-          return;
+        if (kOld === kNew) return;
         _pendingChange[kNew] = _pendingChange[kOld] || { oldKey: kOld };
         _pendingChange[kOld] = void 0;
       } else {
@@ -65547,35 +64767,30 @@ ${content}</tr>
         utilGetSetValue(inputVal, vNew);
       }
       var existingKeyIndex = _orderedKeys.indexOf(kOld);
-      if (existingKeyIndex !== -1)
-        _orderedKeys[existingKeyIndex] = kNew;
-      d.key = kNew;
+      if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
+      d2.key = kNew;
       this.value = kNew;
       scheduleChange();
     }
-    function valueChange(d3_event, d) {
-      if (isReadOnly(d))
-        return;
-      if (typeof d.value !== "string" && !this.value)
-        return;
-      if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === void 0)
-        return;
+    function valueChange(d3_event, d2) {
+      if (isReadOnly(d2)) return;
+      if (typeof d2.value !== "string" && !this.value) return;
+      if (_pendingChange && _pendingChange.hasOwnProperty(d2.key) && _pendingChange[d2.key] === void 0) return;
       _pendingChange = _pendingChange || {};
-      _pendingChange[d.key] = context.cleanTagValue(this.value);
+      _pendingChange[d2.key] = context.cleanTagValue(this.value);
       scheduleChange();
     }
-    function removeTag(d3_event, d) {
-      if (isReadOnly(d))
-        return;
-      if (d.key === "") {
+    function removeTag(d3_event, d2) {
+      if (isReadOnly(d2)) return;
+      if (d2.key === "") {
         _showBlank = false;
         section.reRender();
       } else {
         _orderedKeys = _orderedKeys.filter(function(key) {
-          return key !== d.key;
+          return key !== d2.key;
         });
         _pendingChange = _pendingChange || {};
-        _pendingChange[d.key] = void 0;
+        _pendingChange[d2.key] = void 0;
         scheduleChange();
       }
     }
@@ -65589,15 +64804,13 @@ ${content}</tr>
     function scheduleChange() {
       var entityIDs = _entityIDs;
       window.setTimeout(function() {
-        if (!_pendingChange)
-          return;
-        dispatch10.call("change", this, entityIDs, _pendingChange);
+        if (!_pendingChange) return;
+        dispatch14.call("change", this, entityIDs, _pendingChange);
         _pendingChange = null;
       }, 10);
     }
     section.state = function(val) {
-      if (!arguments.length)
-        return _state;
+      if (!arguments.length) return _state;
       if (_state !== val) {
         _orderedKeys = [];
         _state = val;
@@ -65605,8 +64818,7 @@ ${content}</tr>
       return section;
     };
     section.presets = function(val) {
-      if (!arguments.length)
-        return _presets;
+      if (!arguments.length) return _presets;
       _presets = val;
       if (_presets && _presets.length && _presets[0].isFallback()) {
         section.disclosureExpanded(true);
@@ -65616,14 +64828,12 @@ ${content}</tr>
       return section;
     };
     section.tags = function(val) {
-      if (!arguments.length)
-        return _tags;
+      if (!arguments.length) return _tags;
       _tags = val;
       return section;
     };
     section.entityIDs = function(val) {
-      if (!arguments.length)
-        return _entityIDs;
+      if (!arguments.length) return _entityIDs;
       if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
         _entityIDs = val;
         _orderedKeys = [];
@@ -65631,12 +64841,11 @@ ${content}</tr>
       return section;
     };
     section.readOnlyTags = function(val) {
-      if (!arguments.length)
-        return _readOnlyTags;
+      if (!arguments.length) return _readOnlyTags;
       _readOnlyTags = val;
       return section;
     };
-    return utilRebind(section, dispatch10, "on");
+    return utilRebind(section, dispatch14, "on");
   }
 
   // modules/ui/data_editor.js
@@ -65661,4030 +64870,10912 @@ ${content}</tr>
       ).selectAll("textarea.tag-text").attr("readonly", true).classed("readonly", true);
     }
     dataEditor.datum = function(val) {
-      if (!arguments.length)
-        return _datum;
+      if (!arguments.length) return _datum;
       _datum = val;
       return this;
     };
     return dataEditor;
   }
 
-  // modules/ui/osmose_details.js
-  function uiOsmoseDetails(context) {
-    let _qaItem;
-    function issueString(d, type3) {
-      if (!d)
-        return "";
-      const s = services.osmose.getStrings(d.itemType);
-      return type3 in s ? s[type3] : "";
-    }
-    function osmoseDetails(selection2) {
-      const details = selection2.selectAll(".error-details").data(
-        _qaItem ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      details.exit().remove();
-      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
-      if (issueString(_qaItem, "detail")) {
-        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
-        div.append("h4").call(_t.append("QA.keepRight.detail_description"));
-        div.append("p").attr("class", "qa-details-description-text").html((d) => issueString(d, "detail")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+  // modules/ui/feature_list.js
+  var sexagesimal = __toESM(require_sexagesimal());
+  function uiFeatureList(context) {
+    var _geocodeResults;
+    function featureList(selection2) {
+      var header = selection2.append("div").attr("class", "header fillL");
+      header.append("h2").call(_t.append("inspector.feature_list"));
+      var searchWrap = selection2.append("div").attr("class", "search-header");
+      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
+      var search = searchWrap.append("input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keypress", keypress).on("keydown", keydown).on("input", inputevent);
+      var listWrap = selection2.append("div").attr("class", "inspector-body");
+      var list2 = listWrap.append("div").attr("class", "feature-list");
+      context.on("exit.feature-list", clearSearch);
+      context.map().on("drawn.feature-list", mapDrawn);
+      context.keybinding().on(uiCmd("\u2318F"), focusSearch);
+      function focusSearch(d3_event) {
+        var mode = context.mode() && context.mode().id;
+        if (mode !== "browse") return;
+        d3_event.preventDefault();
+        search.node().focus();
       }
-      const detailsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      const elemsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
-      if (issueString(_qaItem, "fix")) {
-        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
-        div.append("h4").call(_t.append("QA.osmose.fix_title"));
-        div.append("p").html((d) => issueString(d, "fix")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+      function keydown(d3_event) {
+        if (d3_event.keyCode === 27) {
+          search.node().blur();
+        }
       }
-      if (issueString(_qaItem, "trap")) {
-        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
-        div.append("h4").call(_t.append("QA.osmose.trap_title"));
-        div.append("p").html((d) => issueString(d, "trap")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+      function keypress(d3_event) {
+        var q2 = search.property("value"), items = list2.selectAll(".feature-list-item");
+        if (d3_event.keyCode === 13 && // ↩ Return
+        q2.length && items.size()) {
+          click(d3_event, items.datum());
+        }
       }
-      const thisItem = _qaItem;
-      services.osmose.loadIssueDetail(_qaItem).then((d) => {
-        if (!d.elems || d.elems.length === 0)
-          return;
-        if (context.selectedErrorID() !== thisItem.id && context.container().selectAll(`.qaItem.osmose.hover.itemId-${thisItem.id}`).empty())
-          return;
-        if (d.detail) {
-          detailsDiv.append("h4").call(_t.append("QA.osmose.detail_title"));
-          detailsDiv.append("p").html((d2) => d2.detail).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+      function inputevent() {
+        _geocodeResults = void 0;
+        drawList();
+      }
+      function clearSearch() {
+        search.property("value", "");
+        drawList();
+      }
+      function mapDrawn(e3) {
+        if (e3.full) {
+          drawList();
         }
-        elemsDiv.append("h4").call(_t.append("QA.osmose.elems_title"));
-        elemsDiv.append("ul").selectAll("li").data(d.elems).enter().append("li").append("a").attr("href", "#").attr("class", "error_entity_link").text((d2) => d2).each(function() {
-          const link2 = select_default2(this);
-          const entityID = this.textContent;
-          const entity = context.hasEntity(entityID);
-          link2.on("mouseenter", () => {
-            utilHighlightEntities([entityID], true, context);
-          }).on("mouseleave", () => {
-            utilHighlightEntities([entityID], false, context);
-          }).on("click", (d3_event) => {
-            d3_event.preventDefault();
-            utilHighlightEntities([entityID], false, context);
-            const osmlayer = context.layers().layer("osm");
-            if (!osmlayer.enabled()) {
-              osmlayer.enabled(true);
-            }
-            context.map().centerZoom(d.loc, 20);
-            if (entity) {
-              context.enter(modeSelect(context, [entityID]));
-            } else {
-              context.loadEntity(entityID, (err, result) => {
-                if (err)
-                  return;
-                const entity2 = result.data.find((e) => e.id === entityID);
-                if (entity2)
-                  context.enter(modeSelect(context, [entityID]));
-              });
-            }
+      }
+      function features() {
+        var result = [];
+        var graph = context.graph();
+        var visibleCenter = context.map().extent().center();
+        var q2 = search.property("value").toLowerCase();
+        if (!q2) return result;
+        var locationMatch = sexagesimal.pair(q2.toUpperCase()) || dmsMatcher(q2);
+        if (locationMatch) {
+          var loc = [Number(locationMatch[0]), Number(locationMatch[1])];
+          result.push({
+            id: -1,
+            geometry: "point",
+            type: _t("inspector.location"),
+            name: dmsCoordinatePair([loc[1], loc[0]]),
+            location: loc
           });
-          if (entity) {
-            let name = utilDisplayName(entity);
-            if (!name) {
-              const preset = _mainPresetIndex.match(entity, context.graph());
-              name = preset && !preset.isFallback() && preset.name();
-            }
-            if (name) {
-              this.innerText = name;
+        }
+        var idMatch = !locationMatch && q2.match(/(?:^|\W)(node|way|relation|note|[nwr])\W{0,2}0*([1-9]\d*)(?:\W|$)/i);
+        if (idMatch) {
+          var elemType = idMatch[1] === "note" ? idMatch[1] : idMatch[1].charAt(0);
+          var elemId = idMatch[2];
+          result.push({
+            id: elemType + elemId,
+            geometry: elemType === "n" ? "point" : elemType === "w" ? "line" : elemType === "note" ? "note" : "relation",
+            type: elemType === "n" ? _t("inspector.node") : elemType === "w" ? _t("inspector.way") : elemType === "note" ? _t("note.note") : _t("inspector.relation"),
+            name: elemId
+          });
+        }
+        var allEntities = graph.entities;
+        var localResults = [];
+        for (var id2 in allEntities) {
+          var entity = allEntities[id2];
+          if (!entity) continue;
+          var name = utilDisplayName(entity) || "";
+          if (name.toLowerCase().indexOf(q2) < 0) continue;
+          var matched = _mainPresetIndex.match(entity, graph);
+          var type2 = matched && matched.name() || utilDisplayType(entity.id);
+          var extent = entity.extent(graph);
+          var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
+          localResults.push({
+            id: entity.id,
+            entity,
+            geometry: entity.geometry(graph),
+            type: type2,
+            name,
+            distance
+          });
+          if (localResults.length > 100) break;
+        }
+        localResults = localResults.sort(function byDistance(a2, b2) {
+          return a2.distance - b2.distance;
+        });
+        result = result.concat(localResults);
+        (_geocodeResults || []).forEach(function(d2) {
+          if (d2.osm_type && d2.osm_id) {
+            var id3 = osmEntity.id.fromOSM(d2.osm_type, d2.osm_id);
+            var tags = {};
+            tags[d2.class] = d2.type;
+            var attrs = { id: id3, type: d2.osm_type, tags };
+            if (d2.osm_type === "way") {
+              attrs.nodes = ["a", "a"];
             }
+            var tempEntity = osmEntity(attrs);
+            var tempGraph = coreGraph([tempEntity]);
+            var matched2 = _mainPresetIndex.match(tempEntity, tempGraph);
+            var type3 = matched2 && matched2.name() || utilDisplayType(id3);
+            result.push({
+              id: tempEntity.id,
+              geometry: tempEntity.geometry(tempGraph),
+              type: type3,
+              name: d2.display_name,
+              extent: new geoExtent(
+                [Number(d2.boundingbox[3]), Number(d2.boundingbox[0])],
+                [Number(d2.boundingbox[2]), Number(d2.boundingbox[1])]
+              )
+            });
           }
         });
-        context.features().forceVisible(d.elems);
-        context.map().pan([0, 0]);
-      }).catch((err) => {
-        console.log(err);
-      });
-    }
-    osmoseDetails.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return osmoseDetails;
-    };
-    return osmoseDetails;
-  }
-
-  // modules/ui/osmose_header.js
-  function uiOsmoseHeader() {
-    let _qaItem;
-    function issueTitle(d) {
-      const unknown = _t("inspector.unknown");
-      if (!d)
-        return unknown;
-      const s = services.osmose.getStrings(d.itemType);
-      return "title" in s ? s.title : unknown;
-    }
-    function osmoseHeader(selection2) {
-      const header = selection2.selectAll(".qa-header").data(
-        _qaItem ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      header.exit().remove();
-      const headerEnter = header.enter().append("div").attr("class", "qa-header");
-      const svgEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d) => d.id < 0).append("svg").attr("width", "20px").attr("height", "30px").attr("viewbox", "0 0 20 30").attr("class", (d) => `preset-icon-28 qaItem ${d.service} itemId-${d.id} itemType-${d.itemType}`);
-      svgEnter.append("polygon").attr("fill", (d) => services.osmose.getColor(d.item)).attr("class", "qaItem-fill").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
-      svgEnter.append("use").attr("class", "icon-annotation").attr("width", "12px").attr("height", "12px").attr("transform", "translate(4, 5.5)").attr("xlink:href", (d) => d.icon ? "#" + d.icon : "");
-      headerEnter.append("div").attr("class", "qa-header-label").text(issueTitle);
-    }
-    osmoseHeader.issue = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return osmoseHeader;
-    };
-    return osmoseHeader;
-  }
-
-  // modules/ui/view_on_osmose.js
-  function uiViewOnOsmose() {
-    let _qaItem;
-    function viewOnOsmose(selection2) {
-      let url;
-      if (services.osmose && _qaItem instanceof QAItem) {
-        url = services.osmose.itemURL(_qaItem);
+        if (q2.match(/^[0-9]+$/)) {
+          result.push({
+            id: "n" + q2,
+            geometry: "point",
+            type: _t("inspector.node"),
+            name: q2
+          });
+          result.push({
+            id: "w" + q2,
+            geometry: "line",
+            type: _t("inspector.way"),
+            name: q2
+          });
+          result.push({
+            id: "r" + q2,
+            geometry: "relation",
+            type: _t("inspector.relation"),
+            name: q2
+          });
+          result.push({
+            id: "note" + q2,
+            geometry: "note",
+            type: _t("note.note"),
+            name: q2
+          });
+        }
+        return result;
+      }
+      function drawList() {
+        var value = search.property("value");
+        var results = features();
+        list2.classed("filtered", value.length);
+        var resultsIndicator = list2.selectAll(".no-results-item").data([0]).enter().append("button").property("disabled", true).attr("class", "no-results-item").call(svgIcon("#iD-icon-alert", "pre-text"));
+        resultsIndicator.append("span").attr("class", "entity-name");
+        list2.selectAll(".no-results-item .entity-name").html("").call(_t.append("geocoder.no_results_worldwide"));
+        if (services.geocoder) {
+          list2.selectAll(".geocode-item").data([0]).enter().append("button").attr("class", "geocode-item secondary-action").on("click", geocoderSearch).append("div").attr("class", "label").append("span").attr("class", "entity-name").call(_t.append("geocoder.search"));
+        }
+        list2.selectAll(".no-results-item").style("display", value.length && !results.length ? "block" : "none");
+        list2.selectAll(".geocode-item").style("display", value && _geocodeResults === void 0 ? "block" : "none");
+        list2.selectAll(".feature-list-item").data([-1]).remove();
+        var items = list2.selectAll(".feature-list-item").data(results, function(d2) {
+          return d2.id;
+        });
+        var enter = items.enter().insert("button", ".geocode-item").attr("class", "feature-list-item").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
+        var label = enter.append("div").attr("class", "label");
+        label.each(function(d2) {
+          select_default2(this).call(svgIcon("#iD-icon-" + d2.geometry, "pre-text"));
+        });
+        label.append("span").attr("class", "entity-type").text(function(d2) {
+          return d2.type;
+        });
+        label.append("span").attr("class", "entity-name").classed("has-colour", (d2) => d2.entity && d2.entity.type === "relation" && d2.entity.tags.colour && isColourValid(d2.entity.tags.colour)).style("border-color", (d2) => d2.entity && d2.entity.type === "relation" && d2.entity.tags.colour).text(function(d2) {
+          return d2.name;
+        });
+        enter.style("opacity", 0).transition().style("opacity", 1);
+        items.order();
+        items.exit().remove();
+      }
+      function mouseover(d3_event, d2) {
+        if (d2.id === -1) return;
+        utilHighlightEntities([d2.id], true, context);
+      }
+      function mouseout(d3_event, d2) {
+        if (d2.id === -1) return;
+        utilHighlightEntities([d2.id], false, context);
+      }
+      function click(d3_event, d2) {
+        d3_event.preventDefault();
+        if (d2.location) {
+          context.map().centerZoomEase([d2.location[1], d2.location[0]], 19);
+        } else if (d2.entity) {
+          utilHighlightEntities([d2.id], false, context);
+          context.enter(modeSelect(context, [d2.entity.id]));
+          context.map().zoomToEase(d2.entity);
+        } else if (d2.geometry === "note") {
+          const noteId = d2.id.replace(/\D/g, "");
+          context.zoomToNote(noteId);
+        } else {
+          context.zoomToEntity(d2.id);
+        }
+      }
+      function geocoderSearch() {
+        services.geocoder.search(search.property("value"), function(err, resp) {
+          _geocodeResults = resp || [];
+          drawList();
+        });
       }
-      const link2 = selection2.selectAll(".view-on-osmose").data(url ? [url] : []);
-      link2.exit().remove();
-      const linkEnter = link2.enter().append("a").attr("class", "view-on-osmose").attr("target", "_blank").attr("rel", "noopener").attr("href", (d) => d).call(svgIcon("#iD-icon-out-link", "inline"));
-      linkEnter.append("span").call(_t.append("inspector.view_on_osmose"));
     }
-    viewOnOsmose.what = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return viewOnOsmose;
-    };
-    return viewOnOsmose;
+    return featureList;
   }
 
-  // modules/ui/osmose_editor.js
-  function uiOsmoseEditor(context) {
-    const dispatch10 = dispatch_default("change");
-    const qaDetails = uiOsmoseDetails(context);
-    const qaHeader = uiOsmoseHeader(context);
-    let _qaItem;
-    function osmoseEditor(selection2) {
-      const header = selection2.selectAll(".header").data([0]);
-      const headerEnter = header.enter().append("div").attr("class", "header fillL");
-      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
-      headerEnter.append("h2").call(_t.append("QA.osmose.title"));
-      let body = selection2.selectAll(".body").data([0]);
-      body = body.enter().append("div").attr("class", "body").merge(body);
-      let editor = body.selectAll(".qa-editor").data([0]);
-      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
-      const footer = selection2.selectAll(".footer").data([0]);
-      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOsmose(context).what(_qaItem));
+  // modules/ui/entity_editor.js
+  var import_fast_deep_equal9 = __toESM(require_fast_deep_equal());
+
+  // modules/ui/sections/entity_issues.js
+  function uiSectionEntityIssues(context) {
+    var preference = corePreferences("entity-issues.reference.expanded");
+    var _expanded = preference === null ? true : preference === "true";
+    var _entityIDs = [];
+    var _issues = [];
+    var _activeIssueID;
+    var section = uiSection("entity-issues", context).shouldDisplay(function() {
+      return _issues.length > 0;
+    }).label(function() {
+      return _t.append("inspector.title_count", { title: _t("issues.list_title"), count: _issues.length });
+    }).disclosureContent(renderDisclosureContent);
+    context.validator().on("validated.entity_issues", function() {
+      reloadIssues();
+      section.reRender();
+    }).on("focusedIssue.entity_issues", function(issue) {
+      makeActiveIssue(issue.id);
+    });
+    function reloadIssues() {
+      _issues = context.validator().getSharedEntityIssues(_entityIDs, { includeDisabledRules: true });
     }
-    function osmoseSaveSection(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      const isShown = _qaItem && isSelected;
-      let saveSection = selection2.selectAll(".qa-save").data(
-        isShown ? [_qaItem] : [],
-        (d) => `${d.id}-${d.status || 0}`
-      );
-      saveSection.exit().remove();
-      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
-      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
+    function makeActiveIssue(issueID) {
+      _activeIssueID = issueID;
+      section.selection().selectAll(".issue-container").classed("active", function(d2) {
+        return d2.id === _activeIssueID;
+      });
     }
-    function qaSaveButtons(selection2) {
-      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
-      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d) => d.status + d.id);
-      buttonSection.exit().remove();
-      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
-      buttonEnter.append("button").attr("class", "button close-button action");
-      buttonEnter.append("button").attr("class", "button ignore-button action");
-      buttonSection = buttonSection.merge(buttonEnter);
-      buttonSection.select(".close-button").call(_t.append("QA.keepRight.close")).on("click.close", function(d3_event, d) {
-        this.blur();
-        const qaService = services.osmose;
-        if (qaService) {
-          d.newStatus = "done";
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
+    function renderDisclosureContent(selection2) {
+      selection2.classed("grouped-items-area", true);
+      _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
+      var containers = selection2.selectAll(".issue-container").data(_issues, function(d2) {
+        return d2.key;
+      });
+      containers.exit().remove();
+      var containersEnter = containers.enter().append("div").attr("class", "issue-container");
+      var itemsEnter = containersEnter.append("div").attr("class", function(d2) {
+        return "issue severity-" + d2.severity;
+      }).on("mouseover.highlight", function(d3_event, d2) {
+        var ids = d2.entityIds.filter(function(e3) {
+          return _entityIDs.indexOf(e3) === -1;
+        });
+        utilHighlightEntities(ids, true, context);
+      }).on("mouseout.highlight", function(d3_event, d2) {
+        var ids = d2.entityIds.filter(function(e3) {
+          return _entityIDs.indexOf(e3) === -1;
+        });
+        utilHighlightEntities(ids, false, context);
+      });
+      var labelsEnter = itemsEnter.append("div").attr("class", "issue-label");
+      var textEnter = labelsEnter.append("button").attr("class", "issue-text").on("click", function(d3_event, d2) {
+        makeActiveIssue(d2.id);
+        var extent = d2.extent(context.graph());
+        if (extent) {
+          var setZoom = Math.max(context.map().zoom(), 19);
+          context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
         }
       });
-      buttonSection.select(".ignore-button").call(_t.append("QA.keepRight.ignore")).on("click.ignore", function(d3_event, d) {
+      textEnter.each(function(d2) {
+        var iconName = "#iD-icon-" + (d2.severity === "warning" ? "alert" : "error");
+        select_default2(this).call(svgIcon(iconName, "issue-icon"));
+      });
+      textEnter.append("span").attr("class", "issue-message");
+      var infoButton = labelsEnter.append("button").attr("class", "issue-info-button").attr("title", _t("icons.information")).call(svgIcon("#iD-icon-inspect"));
+      infoButton.on("click", function(d3_event) {
+        d3_event.stopPropagation();
+        d3_event.preventDefault();
         this.blur();
-        const qaService = services.osmose;
-        if (qaService) {
-          d.newStatus = "false";
-          qaService.postUpdate(d, (err, item) => dispatch10.call("change", item));
+        var container = select_default2(this.parentNode.parentNode.parentNode);
+        var info = container.selectAll(".issue-info");
+        var isExpanded = info.classed("expanded");
+        _expanded = !isExpanded;
+        corePreferences("entity-issues.reference.expanded", _expanded);
+        if (isExpanded) {
+          info.transition().duration(200).style("max-height", "0px").style("opacity", "0").on("end", function() {
+            info.classed("expanded", false);
+          });
+        } else {
+          info.classed("expanded", true).transition().duration(200).style("max-height", "200px").style("opacity", "1").on("end", function() {
+            info.style("max-height", null);
+          });
+        }
+      });
+      itemsEnter.append("ul").attr("class", "issue-fix-list");
+      containersEnter.append("div").attr("class", "issue-info" + (_expanded ? " expanded" : "")).style("max-height", _expanded ? null : "0").style("opacity", _expanded ? "1" : "0").each(function(d2) {
+        if (typeof d2.reference === "function") {
+          select_default2(this).call(d2.reference);
+        } else {
+          select_default2(this).call(_t.append("inspector.no_documentation_key"));
+        }
+      });
+      containers = containers.merge(containersEnter).classed("active", function(d2) {
+        return d2.id === _activeIssueID;
+      });
+      containers.selectAll(".issue-message").text("").each(function(d2) {
+        return d2.message(context)(select_default2(this));
+      });
+      var fixLists = containers.selectAll(".issue-fix-list");
+      var fixes = fixLists.selectAll(".issue-fix-item").data(function(d2) {
+        return d2.fixes ? d2.fixes(context) : [];
+      }, function(fix) {
+        return fix.id;
+      });
+      fixes.exit().remove();
+      var fixesEnter = fixes.enter().append("li").attr("class", "issue-fix-item");
+      var buttons = fixesEnter.append("button").on("click", function(d3_event, d2) {
+        if (select_default2(this).attr("disabled") || !d2.onClick) return;
+        if (d2.issue.dateLastRanFix && /* @__PURE__ */ new Date() - d2.issue.dateLastRanFix < 1e3) return;
+        d2.issue.dateLastRanFix = /* @__PURE__ */ new Date();
+        utilHighlightEntities(d2.issue.entityIds.concat(d2.entityIds), false, context);
+        new Promise(function(resolve, reject) {
+          d2.onClick(context, resolve, reject);
+          if (d2.onClick.length <= 1) {
+            resolve();
+          }
+        }).then(function() {
+          context.validator().validate();
+        });
+      }).on("mouseover.highlight", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, true, context);
+      }).on("mouseout.highlight", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, false, context);
+      });
+      buttons.each(function(d2) {
+        var iconName = d2.icon || "iD-icon-wrench";
+        if (iconName.startsWith("maki")) {
+          iconName += "-15";
+        }
+        select_default2(this).call(svgIcon("#" + iconName, "fix-icon"));
+      });
+      buttons.append("span").attr("class", "fix-message").each(function(d2) {
+        return d2.title(select_default2(this));
+      });
+      fixesEnter.merge(fixes).selectAll("button").classed("actionable", function(d2) {
+        return d2.onClick;
+      }).attr("disabled", function(d2) {
+        return d2.onClick ? null : "true";
+      }).attr("title", function(d2) {
+        if (d2.disabledReason) {
+          return d2.disabledReason;
         }
+        return null;
       });
     }
-    osmoseEditor.error = function(val) {
-      if (!arguments.length)
-        return _qaItem;
-      _qaItem = val;
-      return osmoseEditor;
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
+        _entityIDs = val;
+        _activeIssueID = null;
+        reloadIssues();
+      }
+      return section;
     };
-    return utilRebind(osmoseEditor, dispatch10, "on");
+    return section;
   }
 
-  // modules/ui/sidebar.js
-  function uiSidebar(context) {
-    var inspector = uiInspector(context);
-    var dataEditor = uiDataEditor(context);
-    var noteEditor = uiNoteEditor(context);
-    var improveOsmEditor = uiImproveOsmEditor(context);
-    var keepRightEditor = uiKeepRightEditor(context);
-    var osmoseEditor = uiOsmoseEditor(context);
-    var _current;
-    var _wasData = false;
-    var _wasNote = false;
-    var _wasQaItem = false;
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    function sidebar(selection2) {
-      var container = context.container();
-      var minWidth = 240;
-      var sidebarWidth;
-      var containerWidth;
-      var dragOffset;
-      selection2.style("min-width", minWidth + "px").style("max-width", "400px").style("width", "33.3333%");
-      var resizer = selection2.append("div").attr("class", "sidebar-resizer").on(_pointerPrefix + "down.sidebar-resizer", pointerdown);
-      var downPointerId, lastClientX, containerLocGetter;
-      function pointerdown(d3_event) {
-        if (downPointerId)
-          return;
-        if ("button" in d3_event && d3_event.button !== 0)
-          return;
-        downPointerId = d3_event.pointerId || "mouse";
-        lastClientX = d3_event.clientX;
-        containerLocGetter = utilFastMouse(container.node());
-        dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
-        sidebarWidth = selection2.node().getBoundingClientRect().width;
-        containerWidth = container.node().getBoundingClientRect().width;
-        var widthPct = sidebarWidth / containerWidth * 100;
-        selection2.style("width", widthPct + "%").style("max-width", "85%");
-        resizer.classed("dragging", true);
-        select_default2(window).on("touchmove.sidebar-resizer", function(d3_event2) {
-          d3_event2.preventDefault();
-        }, { passive: false }).on(_pointerPrefix + "move.sidebar-resizer", pointermove).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", pointerup);
+  // modules/ui/preset_icon.js
+  function uiPresetIcon() {
+    let _preset;
+    let _geometry;
+    function presetIcon(selection2) {
+      selection2.each(render);
+    }
+    function getIcon(p2, geom) {
+      if (p2.isFallback && p2.isFallback()) return geom === "vertex" ? "" : "iD-icon-" + p2.id;
+      if (p2.icon) return p2.icon;
+      if (geom === "line") return "iD-other-line";
+      if (geom === "vertex") return "temaki-vertex";
+      return "maki-marker-stroked";
+    }
+    function renderPointBorder(container, drawPoint) {
+      let pointBorder = container.selectAll(".preset-icon-point-border").data(drawPoint ? [0] : []);
+      pointBorder.exit().remove();
+      let pointBorderEnter = pointBorder.enter();
+      const w2 = 40;
+      const h2 = 40;
+      pointBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-point-border").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2)).append("path").attr("transform", "translate(11.5, 8)").attr("d", "M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z");
+      pointBorder = pointBorderEnter.merge(pointBorder);
+    }
+    function renderCategoryBorder(container, category) {
+      let categoryBorder = container.selectAll(".preset-icon-category-border").data(category ? [0] : []);
+      categoryBorder.exit().remove();
+      let categoryBorderEnter = categoryBorder.enter();
+      const d2 = 60;
+      let svgEnter = categoryBorderEnter.append("svg").attr("class", "preset-icon-fill preset-icon-category-border").attr("width", d2).attr("height", d2).attr("viewBox", "0 0 ".concat(d2, " ").concat(d2));
+      svgEnter.append("path").attr("class", "area").attr("d", "M9.5,7.5 L25.5,7.5 L28.5,12.5 L49.5,12.5 C51.709139,12.5 53.5,14.290861 53.5,16.5 L53.5,43.5 C53.5,45.709139 51.709139,47.5 49.5,47.5 L10.5,47.5 C8.290861,47.5 6.5,45.709139 6.5,43.5 L6.5,12.5 L9.5,7.5 Z");
+      categoryBorder = categoryBorderEnter.merge(categoryBorder);
+      if (category) {
+        categoryBorder.selectAll("path").attr("class", "area ".concat(category.id));
       }
-      function pointermove(d3_event) {
-        if (downPointerId !== (d3_event.pointerId || "mouse"))
-          return;
-        d3_event.preventDefault();
-        var dx = d3_event.clientX - lastClientX;
-        lastClientX = d3_event.clientX;
-        var isRTL = _mainLocalizer.textDirection() === "rtl";
-        var scaleX = isRTL ? 0 : 1;
-        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
-        var x = containerLocGetter(d3_event)[0] - dragOffset;
-        sidebarWidth = isRTL ? containerWidth - x : x;
-        var isCollapsed = selection2.classed("collapsed");
-        var shouldCollapse = sidebarWidth < minWidth;
-        selection2.classed("collapsed", shouldCollapse);
-        if (shouldCollapse) {
-          if (!isCollapsed) {
-            selection2.style(xMarginProperty, "-400px").style("width", "400px");
-            context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
-          }
-        } else {
-          var widthPct = sidebarWidth / containerWidth * 100;
-          selection2.style(xMarginProperty, null).style("width", widthPct + "%");
-          if (isCollapsed) {
-            context.ui().onResize([-sidebarWidth * scaleX, 0]);
-          } else {
-            context.ui().onResize([-dx * scaleX, 0]);
-          }
+    }
+    function renderCircleFill(container, drawVertex) {
+      let vertexFill = container.selectAll(".preset-icon-fill-vertex").data(drawVertex ? [0] : []);
+      vertexFill.exit().remove();
+      let vertexFillEnter = vertexFill.enter();
+      const w2 = 60;
+      const h2 = 60;
+      const d2 = 40;
+      vertexFillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-vertex").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2)).append("circle").attr("cx", w2 / 2).attr("cy", h2 / 2).attr("r", d2 / 2);
+      vertexFill = vertexFillEnter.merge(vertexFill);
+    }
+    function renderSquareFill(container, drawArea, tagClasses) {
+      let fill = container.selectAll(".preset-icon-fill-area").data(drawArea ? [0] : []);
+      fill.exit().remove();
+      let fillEnter = fill.enter();
+      const d2 = 60;
+      const w2 = d2;
+      const h2 = d2;
+      const l2 = d2 * 2 / 3;
+      const c1 = (w2 - l2) / 2;
+      const c2 = c1 + l2;
+      fillEnter = fillEnter.append("svg").attr("class", "preset-icon-fill preset-icon-fill-area").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
+      ["fill", "stroke"].forEach((klass) => {
+        fillEnter.append("path").attr("d", "M".concat(c1, " ").concat(c1, " L").concat(c1, " ").concat(c2, " L").concat(c2, " ").concat(c2, " L").concat(c2, " ").concat(c1, " Z")).attr("class", "area ".concat(klass));
+      });
+      const rVertex = 2.5;
+      [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach((point) => {
+        fillEnter.append("circle").attr("class", "vertex").attr("cx", point[0]).attr("cy", point[1]).attr("r", rVertex);
+      });
+      const rMidpoint = 1.25;
+      [[c1, w2 / 2], [c2, w2 / 2], [h2 / 2, c1], [h2 / 2, c2]].forEach((point) => {
+        fillEnter.append("circle").attr("class", "midpoint").attr("cx", point[0]).attr("cy", point[1]).attr("r", rMidpoint);
+      });
+      fill = fillEnter.merge(fill);
+      fill.selectAll("path.stroke").attr("class", "area stroke ".concat(tagClasses));
+      fill.selectAll("path.fill").attr("class", "area fill ".concat(tagClasses));
+    }
+    function renderLine(container, drawLine, tagClasses) {
+      let line = container.selectAll(".preset-icon-line").data(drawLine ? [0] : []);
+      line.exit().remove();
+      let lineEnter = line.enter();
+      const d2 = 60;
+      const w2 = d2;
+      const h2 = d2;
+      const y2 = Math.round(d2 * 0.72);
+      const l2 = Math.round(d2 * 0.6);
+      const r2 = 2.5;
+      const x12 = (w2 - l2) / 2;
+      const x2 = x12 + l2;
+      lineEnter = lineEnter.append("svg").attr("class", "preset-icon-line").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
+      ["casing", "stroke"].forEach((klass) => {
+        lineEnter.append("path").attr("d", "M".concat(x12, " ").concat(y2, " L").concat(x2, " ").concat(y2)).attr("class", "line ".concat(klass));
+      });
+      [[x12 - 1, y2], [x2 + 1, y2]].forEach((point) => {
+        lineEnter.append("circle").attr("class", "vertex").attr("cx", point[0]).attr("cy", point[1]).attr("r", r2);
+      });
+      line = lineEnter.merge(line);
+      line.selectAll("path.stroke").attr("class", "line stroke ".concat(tagClasses));
+      line.selectAll("path.casing").attr("class", "line casing ".concat(tagClasses));
+    }
+    function renderRoute(container, drawRoute, p2) {
+      let route = container.selectAll(".preset-icon-route").data(drawRoute ? [0] : []);
+      route.exit().remove();
+      let routeEnter = route.enter();
+      const d2 = 60;
+      const w2 = d2;
+      const h2 = d2;
+      const y12 = Math.round(d2 * 0.8);
+      const y2 = Math.round(d2 * 0.68);
+      const l2 = Math.round(d2 * 0.6);
+      const r2 = 2;
+      const x12 = (w2 - l2) / 2;
+      const x2 = x12 + l2 / 3;
+      const x3 = x2 + l2 / 3;
+      const x4 = x3 + l2 / 3;
+      routeEnter = routeEnter.append("svg").attr("class", "preset-icon-route").attr("width", w2).attr("height", h2).attr("viewBox", "0 0 ".concat(w2, " ").concat(h2));
+      ["casing", "stroke"].forEach((klass) => {
+        routeEnter.append("path").attr("d", "M".concat(x12, " ").concat(y12, " L").concat(x2, " ").concat(y2)).attr("class", "segment0 line ".concat(klass));
+        routeEnter.append("path").attr("d", "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y12)).attr("class", "segment1 line ".concat(klass));
+        routeEnter.append("path").attr("d", "M".concat(x3, " ").concat(y12, " L").concat(x4, " ").concat(y2)).attr("class", "segment2 line ".concat(klass));
+      });
+      [[x12, y12], [x2, y2], [x3, y12], [x4, y2]].forEach((point) => {
+        routeEnter.append("circle").attr("class", "vertex").attr("cx", point[0]).attr("cy", point[1]).attr("r", r2);
+      });
+      route = routeEnter.merge(route);
+      if (drawRoute) {
+        let routeType = p2.tags.type === "waterway" ? "waterway" : p2.tags.route;
+        const segmentPresetIDs = routeSegments[routeType];
+        for (let i3 in segmentPresetIDs) {
+          const segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i3]);
+          const segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, "");
+          route.selectAll("path.stroke.segment".concat(i3)).attr("class", "segment".concat(i3, " line stroke ").concat(segmentTagClasses));
+          route.selectAll("path.casing.segment".concat(i3)).attr("class", "segment".concat(i3, " line casing ").concat(segmentTagClasses));
         }
       }
-      function pointerup(d3_event) {
-        if (downPointerId !== (d3_event.pointerId || "mouse"))
-          return;
-        downPointerId = null;
-        resizer.classed("dragging", false);
-        select_default2(window).on("touchmove.sidebar-resizer", null).on(_pointerPrefix + "move.sidebar-resizer", null).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", null);
+    }
+    function renderSvgIcon(container, picon, geom, isFramed, category, tagClasses) {
+      const isMaki = picon && /^maki-/.test(picon);
+      const isTemaki = picon && /^temaki-/.test(picon);
+      const isFa = picon && /^fa[srb]-/.test(picon);
+      const isR\u00F6ntgen = picon && /^roentgen-/.test(picon);
+      const isiDIcon = picon && !(isMaki || isTemaki || isFa || isR\u00F6ntgen);
+      let icon2 = container.selectAll(".preset-icon").data(picon ? [0] : []);
+      icon2.exit().remove();
+      icon2 = icon2.enter().append("div").attr("class", "preset-icon").call(svgIcon("")).merge(icon2);
+      icon2.attr("class", "preset-icon " + (geom ? geom + "-geom" : "")).classed("category", category).classed("framed", isFramed).classed("preset-icon-iD", isiDIcon);
+      icon2.selectAll("svg").attr("class", "icon " + picon + " " + (!isiDIcon && geom !== "line" ? "" : tagClasses));
+      icon2.selectAll("use").attr("href", "#" + picon);
+    }
+    function renderImageIcon(container, imageURL) {
+      let imageIcon = container.selectAll("img.image-icon").data(imageURL ? [0] : []);
+      imageIcon.exit().remove();
+      imageIcon = imageIcon.enter().append("img").attr("class", "image-icon").on("load", () => container.classed("showing-img", true)).on("error", () => container.classed("showing-img", false)).merge(imageIcon);
+      imageIcon.attr("src", imageURL);
+    }
+    const routeSegments = {
+      bicycle: ["highway/cycleway", "highway/cycleway", "highway/cycleway"],
+      bus: ["highway/unclassified", "highway/secondary", "highway/primary"],
+      trolleybus: ["highway/unclassified", "highway/secondary", "highway/primary"],
+      detour: ["highway/tertiary", "highway/residential", "highway/unclassified"],
+      ferry: ["route/ferry", "route/ferry", "route/ferry"],
+      foot: ["highway/footway", "highway/footway", "highway/footway"],
+      hiking: ["highway/path", "highway/path", "highway/path"],
+      horse: ["highway/bridleway", "highway/bridleway", "highway/bridleway"],
+      light_rail: ["railway/light_rail", "railway/light_rail", "railway/light_rail"],
+      monorail: ["railway/monorail", "railway/monorail", "railway/monorail"],
+      mtb: ["highway/path", "highway/track", "highway/bridleway"],
+      pipeline: ["man_made/pipeline", "man_made/pipeline", "man_made/pipeline"],
+      piste: ["piste/downhill", "piste/hike", "piste/nordic"],
+      power: ["power/line", "power/line", "power/line"],
+      road: ["highway/secondary", "highway/primary", "highway/trunk"],
+      subway: ["railway/subway", "railway/subway", "railway/subway"],
+      train: ["railway/rail", "railway/rail", "railway/rail"],
+      tram: ["railway/tram", "railway/tram", "railway/tram"],
+      railway: ["railway/rail", "railway/rail", "railway/rail"],
+      waterway: ["waterway/stream", "waterway/stream", "waterway/stream"]
+    };
+    function render() {
+      let p2 = _preset.apply(this, arguments);
+      let geom = _geometry ? _geometry.apply(this, arguments) : null;
+      if (geom === "relation" && p2.tags && (p2.tags.type === "route" && p2.tags.route && routeSegments[p2.tags.route] || p2.tags.type === "waterway")) {
+        geom = "route";
       }
-      var featureListWrap = selection2.append("div").attr("class", "feature-list-pane").call(uiFeatureList(context));
-      var inspectorWrap = selection2.append("div").attr("class", "inspector-hidden inspector-wrap");
-      var hoverModeSelect = function(targets) {
-        context.container().selectAll(".feature-list-item button").classed("hover", false);
-        if (context.selectedIDs().length > 1 && targets && targets.length) {
-          var elements = context.container().selectAll(".feature-list-item button").filter(function(node) {
-            return targets.indexOf(node) !== -1;
-          });
-          if (!elements.empty()) {
-            elements.classed("hover", true);
-          }
-        }
-      };
-      sidebar.hoverModeSelect = throttle_default(hoverModeSelect, 200);
-      function hover(targets) {
-        var datum2 = targets && targets.length && targets[0];
-        if (datum2 && datum2.__featurehash__) {
-          _wasData = true;
-          sidebar.show(dataEditor.datum(datum2));
-          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
-        } else if (datum2 instanceof osmNote) {
-          if (context.mode().id === "drag-note")
-            return;
-          _wasNote = true;
-          var osm = services.osm;
-          if (osm) {
-            datum2 = osm.getNote(datum2.id);
-          }
-          sidebar.show(noteEditor.note(datum2));
-          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
-        } else if (datum2 instanceof QAItem) {
-          _wasQaItem = true;
-          var errService = services[datum2.service];
-          if (errService) {
-            datum2 = errService.getError(datum2.id);
-          }
-          var errEditor;
-          if (datum2.service === "keepRight") {
-            errEditor = keepRightEditor;
-          } else if (datum2.service === "osmose") {
-            errEditor = osmoseEditor;
-          } else {
-            errEditor = improveOsmEditor;
-          }
-          context.container().selectAll(".qaItem." + datum2.service).classed("hover", function(d) {
-            return d.id === datum2.id;
-          });
-          sidebar.show(errEditor.error(datum2));
-          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
-        } else if (!_current && datum2 instanceof osmEntity) {
-          featureListWrap.classed("inspector-hidden", true);
-          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", true);
-          if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum2.id]) || inspector.state() !== "hover") {
-            inspector.state("hover").entityIDs([datum2.id]).newFeature(false);
-            inspectorWrap.call(inspector);
-          }
-        } else if (!_current) {
-          featureListWrap.classed("inspector-hidden", false);
-          inspectorWrap.classed("inspector-hidden", true);
-          inspector.state("hide");
-        } else if (_wasData || _wasNote || _wasQaItem) {
-          _wasNote = false;
-          _wasData = false;
-          _wasQaItem = false;
-          context.container().selectAll(".note").classed("hover", false);
-          context.container().selectAll(".qaItem").classed("hover", false);
-          sidebar.hide();
+      const showThirdPartyIcons = corePreferences("preferences.privacy.thirdpartyicons") || "true";
+      const isFallback = p2.isFallback && p2.isFallback();
+      const imageURL = showThirdPartyIcons === "true" && p2.imageURL;
+      const picon = getIcon(p2, geom);
+      const isCategory = !p2.setTags;
+      const drawPoint = false;
+      const drawVertex = picon !== null && geom === "vertex";
+      const drawLine = picon && geom === "line" && !isFallback && !isCategory;
+      const drawArea = picon && geom === "area" && !isFallback && !isCategory;
+      const drawRoute = picon && geom === "route";
+      const isFramed = drawVertex || drawArea || drawLine || drawRoute || isCategory;
+      let tags = !isCategory ? p2.setTags({}, geom) : {};
+      for (let k2 in tags) {
+        if (tags[k2] === "*") {
+          tags[k2] = "yes";
         }
       }
-      sidebar.hover = throttle_default(hover, 200);
-      sidebar.intersects = function(extent) {
-        var rect = selection2.node().getBoundingClientRect();
-        return extent.intersects([
-          context.projection.invert([0, rect.height]),
-          context.projection.invert([rect.width, 0])
-        ]);
-      };
-      sidebar.select = function(ids, newFeature) {
-        sidebar.hide();
-        if (ids && ids.length) {
-          var entity = ids.length === 1 && context.entity(ids[0]);
-          if (entity && newFeature && selection2.classed("collapsed")) {
-            var extent = entity.extent(context.graph());
-            sidebar.expand(sidebar.intersects(extent));
-          }
-          featureListWrap.classed("inspector-hidden", true);
-          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", false);
-          inspector.state("select").entityIDs(ids).newFeature(newFeature);
-          inspectorWrap.call(inspector);
-        } else {
-          inspector.state("hide");
-        }
-      };
-      sidebar.showPresetList = function() {
-        inspector.showList();
-      };
-      sidebar.show = function(component, element) {
-        featureListWrap.classed("inspector-hidden", true);
-        inspectorWrap.classed("inspector-hidden", true);
-        if (_current)
-          _current.remove();
-        _current = selection2.append("div").attr("class", "sidebar-component").call(component, element);
-      };
-      sidebar.hide = function() {
-        featureListWrap.classed("inspector-hidden", false);
-        inspectorWrap.classed("inspector-hidden", true);
-        if (_current)
-          _current.remove();
-        _current = null;
-      };
-      sidebar.expand = function(moveMap) {
-        if (selection2.classed("collapsed")) {
-          sidebar.toggle(moveMap);
-        }
-      };
-      sidebar.collapse = function(moveMap) {
-        if (!selection2.classed("collapsed")) {
-          sidebar.toggle(moveMap);
-        }
-      };
-      sidebar.toggle = function(moveMap) {
-        if (context.inIntro())
-          return;
-        var isCollapsed = selection2.classed("collapsed");
-        var isCollapsing = !isCollapsed;
-        var isRTL = _mainLocalizer.textDirection() === "rtl";
-        var scaleX = isRTL ? 0 : 1;
-        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
-        sidebarWidth = selection2.node().getBoundingClientRect().width;
-        selection2.style("width", sidebarWidth + "px");
-        var startMargin, endMargin, lastMargin;
-        if (isCollapsing) {
-          startMargin = lastMargin = 0;
-          endMargin = -sidebarWidth;
-        } else {
-          startMargin = lastMargin = -sidebarWidth;
-          endMargin = 0;
-        }
-        if (!isCollapsing) {
-          selection2.classed("collapsed", isCollapsing);
-        }
-        selection2.transition().style(xMarginProperty, endMargin + "px").tween("panner", function() {
-          var i2 = number_default(startMargin, endMargin);
-          return function(t) {
-            var dx = lastMargin - Math.round(i2(t));
-            lastMargin = lastMargin - dx;
-            context.ui().onResize(moveMap ? void 0 : [dx * scaleX, 0]);
-          };
-        }).on("end", function() {
-          if (isCollapsing) {
-            selection2.classed("collapsed", isCollapsing);
-          }
-          if (!isCollapsing) {
-            var containerWidth2 = container.node().getBoundingClientRect().width;
-            var widthPct = sidebarWidth / containerWidth2 * 100;
-            selection2.style(xMarginProperty, null).style("width", widthPct + "%");
-          }
-        });
-      };
-      resizer.on("dblclick", function(d3_event) {
+      let tagClasses = svgTagClasses().getClassesString(tags, "");
+      let selection2 = select_default2(this);
+      let container = selection2.selectAll(".preset-icon-container").data([0]);
+      container = container.enter().append("div").attr("class", "preset-icon-container").merge(container);
+      container.classed("showing-img", !!imageURL).classed("fallback", isFallback);
+      renderCategoryBorder(container, isCategory && p2);
+      renderPointBorder(container, drawPoint);
+      renderCircleFill(container, drawVertex);
+      renderSquareFill(container, drawArea, tagClasses);
+      renderLine(container, drawLine, tagClasses);
+      renderRoute(container, drawRoute, p2);
+      renderSvgIcon(container, picon, geom, isFramed, isCategory, tagClasses);
+      renderImageIcon(container, imageURL);
+    }
+    presetIcon.preset = function(val) {
+      if (!arguments.length) return _preset;
+      _preset = utilFunctor(val);
+      return presetIcon;
+    };
+    presetIcon.geometry = function(val) {
+      if (!arguments.length) return _geometry;
+      _geometry = utilFunctor(val);
+      return presetIcon;
+    };
+    return presetIcon;
+  }
+
+  // modules/ui/sections/feature_type.js
+  function uiSectionFeatureType(context) {
+    var dispatch14 = dispatch_default("choose");
+    var _entityIDs = [];
+    var _presets = [];
+    var _tagReference;
+    var section = uiSection("feature-type", context).label(() => _t.append("inspector.feature_type")).disclosureContent(renderDisclosureContent);
+    function renderDisclosureContent(selection2) {
+      selection2.classed("preset-list-item", true);
+      selection2.classed("mixed-types", _presets.length > 1);
+      var presetButtonWrap = selection2.selectAll(".preset-list-button-wrap").data([0]).enter().append("div").attr("class", "preset-list-button-wrap");
+      var presetButton = presetButtonWrap.append("button").attr("class", "preset-list-button preset-reset").call(
+        uiTooltip().title(() => _t.append("inspector.back_tooltip")).placement("bottom")
+      );
+      presetButton.append("div").attr("class", "preset-icon-container");
+      presetButton.append("div").attr("class", "label").append("div").attr("class", "label-inner");
+      presetButtonWrap.append("div").attr("class", "accessory-buttons");
+      var tagReferenceBodyWrap = selection2.selectAll(".tag-reference-body-wrap").data([0]);
+      tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append("div").attr("class", "tag-reference-body-wrap").merge(tagReferenceBodyWrap);
+      if (_tagReference) {
+        selection2.selectAll(".preset-list-button-wrap .accessory-buttons").style("display", _presets.length === 1 ? null : "none").call(_tagReference.button);
+        tagReferenceBodyWrap.style("display", _presets.length === 1 ? null : "none").call(_tagReference.body);
+      }
+      selection2.selectAll(".preset-reset").on("click", function() {
+        dispatch14.call("choose", this, _presets);
+      }).on("pointerdown pointerup mousedown mouseup", function(d3_event) {
         d3_event.preventDefault();
-        if (d3_event.sourceEvent) {
-          d3_event.sourceEvent.preventDefault();
-        }
-        sidebar.toggle();
+        d3_event.stopPropagation();
       });
-      context.map().on("crossEditableZoom.sidebar", function(within) {
-        if (!within && !selection2.select(".inspector-hover").empty()) {
-          hover([]);
-        }
+      var geometries = entityGeometries();
+      selection2.select(".preset-list-item button").call(
+        uiPresetIcon().geometry(_presets.length === 1 ? geometries.length === 1 && geometries[0] : null).preset(_presets.length === 1 ? _presets[0] : _mainPresetIndex.item("point"))
+      );
+      var names = _presets.length === 1 ? [
+        _presets[0].nameLabel(),
+        _presets[0].subtitleLabel()
+      ].filter(Boolean) : [_t.append("inspector.multiple_types")];
+      var label = selection2.select(".label-inner");
+      var nameparts = label.selectAll(".namepart").data(names, (d2) => d2.stringId);
+      nameparts.exit().remove();
+      nameparts.enter().append("div").attr("class", "namepart").text("").each(function(d2) {
+        d2(select_default2(this));
       });
     }
-    sidebar.showPresetList = function() {
-    };
-    sidebar.hover = function() {
-    };
-    sidebar.hover.cancel = function() {
-    };
-    sidebar.intersects = function() {
-    };
-    sidebar.select = function() {
-    };
-    sidebar.show = function() {
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return section;
     };
-    sidebar.hide = function() {
+    section.presets = function(val) {
+      if (!arguments.length) return _presets;
+      if (!utilArrayIdentical(val, _presets)) {
+        _presets = val;
+        if (_presets.length === 1) {
+          _tagReference = uiTagReference(_presets[0].reference(), context).showing(false);
+        }
+      }
+      return section;
     };
-    sidebar.expand = function() {
+    function entityGeometries() {
+      var counts = {};
+      for (var i3 in _entityIDs) {
+        var geometry = context.graph().geometry(_entityIDs[i3]);
+        if (!counts[geometry]) counts[geometry] = 0;
+        counts[geometry] += 1;
+      }
+      return Object.keys(counts).sort(function(geom1, geom2) {
+        return counts[geom2] - counts[geom1];
+      });
+    }
+    return utilRebind(section, dispatch14, "on");
+  }
+
+  // modules/ui/form_fields.js
+  function uiFormFields(context) {
+    var moreCombo = uiCombobox(context, "more-fields").minItems(1);
+    var _fieldsArr = [];
+    var _lastPlaceholder = "";
+    var _state = "";
+    var _klass = "";
+    function formFields(selection2) {
+      var allowedFields = _fieldsArr.filter(function(field) {
+        return field.isAllowed();
+      });
+      var shown = allowedFields.filter(function(field) {
+        return field.isShown();
+      });
+      var notShown = allowedFields.filter(function(field) {
+        return !field.isShown();
+      }).sort(function(a2, b2) {
+        return a2.universal === b2.universal ? 0 : a2.universal ? 1 : -1;
+      });
+      var container = selection2.selectAll(".form-fields-container").data([0]);
+      container = container.enter().append("div").attr("class", "form-fields-container " + (_klass || "")).merge(container);
+      var fields = container.selectAll(".wrap-form-field").data(shown, function(d2) {
+        return d2.id + (d2.entityIDs ? d2.entityIDs.join() : "");
+      });
+      fields.exit().remove();
+      var enter = fields.enter().append("div").attr("class", function(d2) {
+        return "wrap-form-field wrap-form-field-" + d2.safeid;
+      });
+      fields = fields.merge(enter);
+      fields.order().each(function(d2) {
+        select_default2(this).call(d2.render);
+      });
+      var titles = [];
+      var moreFields = notShown.map(function(field) {
+        var title = field.title();
+        titles.push(title);
+        var terms = field.terms();
+        if (field.key) terms.push(field.key);
+        if (field.keys) terms = terms.concat(field.keys);
+        return {
+          display: field.label(),
+          value: title,
+          title,
+          field,
+          terms
+        };
+      });
+      var placeholder = titles.slice(0, 3).join(", ") + (titles.length > 3 ? "\u2026" : "");
+      var more = selection2.selectAll(".more-fields").data(_state === "hover" || moreFields.length === 0 ? [] : [0]);
+      more.exit().remove();
+      var moreEnter = more.enter().append("div").attr("class", "more-fields").append("label");
+      moreEnter.append("span").call(_t.append("inspector.add_fields"));
+      more = moreEnter.merge(more);
+      var input = more.selectAll(".value").data([0]);
+      input.exit().remove();
+      input = input.enter().append("input").attr("class", "value").attr("type", "text").attr("placeholder", placeholder).call(utilNoAuto).merge(input);
+      input.call(utilGetSetValue, "").call(
+        moreCombo.data(moreFields).on("accept", function(d2) {
+          if (!d2) return;
+          var field = d2.field;
+          field.show();
+          selection2.call(formFields);
+          field.focus();
+        })
+      );
+      if (_lastPlaceholder !== placeholder) {
+        input.attr("placeholder", placeholder);
+        _lastPlaceholder = placeholder;
+      }
+    }
+    formFields.fieldsArr = function(val) {
+      if (!arguments.length) return _fieldsArr;
+      _fieldsArr = val || [];
+      return formFields;
     };
-    sidebar.collapse = function() {
+    formFields.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      return formFields;
     };
-    sidebar.toggle = function() {
+    formFields.klass = function(val) {
+      if (!arguments.length) return _klass;
+      _klass = val;
+      return formFields;
     };
-    return sidebar;
+    return formFields;
   }
 
-  // modules/modes/draw_area.js
-  function modeDrawArea(context, wayID, startGraph, button) {
-    var mode = {
-      button,
-      id: "draw-area"
-    };
-    var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on("rejectedSelfIntersection.modeDrawArea", function() {
-      context.ui().flash.iconName("#iD-icon-no").label(_t.append("self_intersection.error.areas"))();
-    });
-    mode.wayID = wayID;
-    mode.enter = function() {
-      context.install(behavior);
+  // modules/ui/sections/preset_fields.js
+  function uiSectionPresetFields(context) {
+    var section = uiSection("preset-fields", context).label(() => _t.append("inspector.fields")).disclosureContent(renderDisclosureContent);
+    var dispatch14 = dispatch_default("change", "revert");
+    var formFields = uiFormFields(context);
+    var _state;
+    var _fieldsArr;
+    var _presets = [];
+    var _tags;
+    var _entityIDs;
+    function renderDisclosureContent(selection2) {
+      if (!_fieldsArr) {
+        var graph = context.graph();
+        var geometries = Object.keys(_entityIDs.reduce(function(geoms, entityID) {
+          geoms[graph.entity(entityID).geometry(graph)] = true;
+          return geoms;
+        }, {}));
+        const loc = _entityIDs.reduce(function(extent, entityID) {
+          var entity = context.graph().entity(entityID);
+          return extent.extend(entity.extent(context.graph()));
+        }, geoExtent()).center();
+        var presetsManager = _mainPresetIndex;
+        var allFields = [];
+        var allMoreFields = [];
+        var sharedTotalFields;
+        _presets.forEach(function(preset) {
+          var fields = preset.fields(loc);
+          var moreFields = preset.moreFields(loc);
+          allFields = utilArrayUnion(allFields, fields);
+          allMoreFields = utilArrayUnion(allMoreFields, moreFields);
+          if (!sharedTotalFields) {
+            sharedTotalFields = utilArrayUnion(fields, moreFields);
+          } else {
+            sharedTotalFields = sharedTotalFields.filter(function(field) {
+              return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
+            });
+          }
+        });
+        var sharedFields = allFields.filter(function(field) {
+          return sharedTotalFields.indexOf(field) !== -1;
+        });
+        var sharedMoreFields = allMoreFields.filter(function(field) {
+          return sharedTotalFields.indexOf(field) !== -1;
+        });
+        _fieldsArr = [];
+        sharedFields.forEach(function(field) {
+          if (field.matchAllGeometry(geometries)) {
+            _fieldsArr.push(
+              uiField(context, field, _entityIDs)
+            );
+          }
+        });
+        var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
+        if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field("restrictions")) {
+          _fieldsArr.push(
+            uiField(context, presetsManager.field("restrictions"), _entityIDs)
+          );
+        }
+        var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
+        additionalFields.sort(function(field1, field2) {
+          return field1.title().localeCompare(field2.title(), _mainLocalizer.localeCode());
+        });
+        additionalFields.forEach(function(field) {
+          if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
+            _fieldsArr.push(
+              uiField(context, field, _entityIDs, { show: false })
+            );
+          }
+        });
+        _fieldsArr.forEach(function(field) {
+          field.on("change", function(t2, onInput) {
+            dispatch14.call("change", field, _entityIDs, t2, onInput);
+          }).on("revert", function(keys2) {
+            dispatch14.call("revert", field, keys2);
+          });
+        });
+      }
+      _fieldsArr.forEach(function(field) {
+        field.state(_state).tags(_tags);
+      });
+      selection2.call(
+        formFields.fieldsArr(_fieldsArr).state(_state).klass("grouped-items-area")
+      );
+    }
+    section.presets = function(val) {
+      if (!arguments.length) return _presets;
+      if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
+        _presets = val;
+        _fieldsArr = null;
+      }
+      return section;
     };
-    mode.exit = function() {
-      context.uninstall(behavior);
+    section.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      return section;
     };
-    mode.selectedIDs = function() {
-      return [wayID];
+    section.tags = function(val) {
+      if (!arguments.length) return _tags;
+      _tags = val;
+      return section;
     };
-    mode.activeID = function() {
-      return behavior && behavior.activeID() || [];
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
+        _entityIDs = val;
+        _fieldsArr = null;
+      }
+      return section;
     };
-    return mode;
+    return utilRebind(section, dispatch14, "on");
   }
 
-  // modules/modes/add_area.js
-  function modeAddArea(context, mode) {
-    mode.id = "add-area";
-    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
-    var defaultTags = { area: "yes" };
-    if (mode.preset)
-      defaultTags = mode.preset.setTags(defaultTags, "area");
-    function actionClose(wayId) {
-      return function(graph) {
-        return graph.replace(graph.entity(wayId).close());
-      };
+  // modules/ui/sections/raw_member_editor.js
+  function uiSectionRawMemberEditor(context) {
+    var section = uiSection("raw-member-editor", context).shouldDisplay(function() {
+      if (!_entityIDs || _entityIDs.length !== 1) return false;
+      var entity = context.hasEntity(_entityIDs[0]);
+      return entity && entity.type === "relation";
+    }).label(function() {
+      var entity = context.hasEntity(_entityIDs[0]);
+      if (!entity) return "";
+      var gt2 = entity.members.length > _maxMembers ? ">" : "";
+      var count = gt2 + entity.members.slice(0, _maxMembers).length;
+      return _t.append("inspector.title_count", { title: _t("inspector.members"), count });
+    }).disclosureContent(renderDisclosureContent);
+    var taginfo = services.taginfo;
+    var _entityIDs;
+    var _maxMembers = 1e3;
+    function downloadMember(d3_event, d2) {
+      d3_event.preventDefault();
+      select_default2(this).classed("loading", true);
+      context.loadEntity(d2.id, function() {
+        section.reRender();
+      });
     }
-    function start2(loc) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags });
-      context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionClose(way.id)
-      );
-      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    function zoomToMember(d3_event, d2) {
+      d3_event.preventDefault();
+      var entity = context.entity(d2.id);
+      context.map().zoomToEase(entity);
+      utilHighlightEntities([d2.id], true, context);
     }
-    function startFromWay(loc, edge) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags });
-      context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionClose(way.id),
-        actionAddMidpoint({ loc, edge }, node)
-      );
-      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    function selectMember(d3_event, d2) {
+      d3_event.preventDefault();
+      utilHighlightEntities([d2.id], false, context);
+      var entity = context.entity(d2.id);
+      var mapExtent = context.map().extent();
+      if (!entity.intersects(mapExtent, context.graph())) {
+        context.map().zoomToEase(entity);
+      }
+      context.enter(modeSelect(context, [d2.id]));
     }
-    function startFromNode(node) {
-      var startGraph = context.graph();
-      var way = osmWay({ tags: defaultTags });
-      context.perform(
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionClose(way.id)
-      );
-      context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
+    function changeRole(d3_event, d2) {
+      var oldRole = d2.role;
+      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
+      if (oldRole !== newRole) {
+        var member = { id: d2.id, type: d2.type, role: newRole };
+        context.perform(
+          actionChangeMember(d2.relation.id, member, d2.index),
+          _t("operations.change_role.annotation", {
+            n: 1
+          })
+        );
+        context.validator().validate();
+      }
     }
-    mode.enter = function() {
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
-    };
-    return mode;
-  }
-
-  // modules/modes/add_line.js
-  function modeAddLine(context, mode) {
-    mode.id = "add-line";
-    var behavior = behaviorAddWay(context).on("start", start2).on("startFromWay", startFromWay).on("startFromNode", startFromNode);
-    var defaultTags = {};
-    if (mode.preset)
-      defaultTags = mode.preset.setTags(defaultTags, "line");
-    function start2(loc) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags });
+    function deleteMember(d3_event, d2) {
+      utilHighlightEntities([d2.id], false, context);
       context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id)
+        actionDeleteMember(d2.relation.id, d2.index),
+        _t("operations.delete_member.annotation", {
+          n: 1
+        })
       );
-      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+      if (!context.hasEntity(d2.relation.id)) {
+        context.enter(modeBrowse(context));
+      } else {
+        context.validator().validate();
+      }
     }
-    function startFromWay(loc, edge) {
-      var startGraph = context.graph();
-      var node = osmNode({ loc });
-      var way = osmWay({ tags: defaultTags });
-      context.perform(
-        actionAddEntity(node),
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id),
-        actionAddMidpoint({ loc, edge }, node)
-      );
-      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
-    }
-    function startFromNode(node) {
-      var startGraph = context.graph();
-      var way = osmWay({ tags: defaultTags });
-      context.perform(
-        actionAddEntity(way),
-        actionAddVertex(way.id, node.id)
+    function renderDisclosureContent(selection2) {
+      var entityID = _entityIDs[0];
+      var memberships = [];
+      var entity = context.entity(entityID);
+      entity.members.slice(0, _maxMembers).forEach(function(member, index) {
+        memberships.push({
+          index,
+          id: member.id,
+          type: member.type,
+          role: member.role,
+          relation: entity,
+          member: context.hasEntity(member.id),
+          domId: utilUniqueDomId(entityID + "-member-" + index)
+        });
+      });
+      var list2 = selection2.selectAll(".member-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "member-list").merge(list2);
+      var items = list2.selectAll("li").data(memberships, function(d2) {
+        return osmEntity.key(d2.relation) + "," + d2.index + "," + (d2.member ? osmEntity.key(d2.member) : "incomplete");
+      });
+      items.exit().each(unbind).remove();
+      var itemsEnter = items.enter().append("li").attr("class", "member-row form-field").classed("member-incomplete", function(d2) {
+        return !d2.member;
+      });
+      itemsEnter.each(function(d2) {
+        var item = select_default2(this);
+        var label = item.append("label").attr("class", "field-label").attr("for", d2.domId);
+        if (d2.member) {
+          item.on("mouseover", function() {
+            utilHighlightEntities([d2.id], true, context);
+          }).on("mouseout", function() {
+            utilHighlightEntities([d2.id], false, context);
+          });
+          var labelLink = label.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectMember);
+          labelLink.append("span").attr("class", "member-entity-type").text(function(d4) {
+            var matched = _mainPresetIndex.match(d4.member, context.graph());
+            return matched && matched.name() || utilDisplayType(d4.member.id);
+          });
+          labelLink.append("span").attr("class", "member-entity-name").classed("has-colour", (d4) => d4.member.type === "relation" && d4.member.tags.colour && isColourValid(d4.member.tags.colour)).style("border-color", (d4) => d4.member.type === "relation" && d4.member.tags.colour).text(function(d4) {
+            return utilDisplayName(d4.member);
+          });
+          label.append("button").attr("title", _t("icons.remove")).attr("class", "remove member-delete").call(svgIcon("#iD-operation-delete"));
+          label.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToMember);
+        } else {
+          var labelText = label.append("span").attr("class", "label-text");
+          labelText.append("span").attr("class", "member-entity-type").call(_t.append("inspector." + d2.type, { id: d2.id }));
+          labelText.append("span").attr("class", "member-entity-name").call(_t.append("inspector.incomplete", { id: d2.id }));
+          label.append("button").attr("class", "member-download").attr("title", _t("icons.download")).call(svgIcon("#iD-icon-load")).on("click", downloadMember);
+        }
+      });
+      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
+      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d2) {
+        return d2.domId;
+      }).property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
+      if (taginfo) {
+        wrapEnter.each(bindTypeahead);
+      }
+      items = items.merge(itemsEnter).order();
+      items.select("input.member-role").property("value", function(d2) {
+        return d2.role;
+      }).on("blur", changeRole).on("change", changeRole);
+      items.select("button.member-delete").on("click", deleteMember);
+      var dragOrigin, targetIndex;
+      items.call(
+        drag_default().on("start", function(d3_event) {
+          dragOrigin = {
+            x: d3_event.x,
+            y: d3_event.y
+          };
+          targetIndex = null;
+        }).on("drag", function(d3_event) {
+          var x2 = d3_event.x - dragOrigin.x, y2 = d3_event.y - dragOrigin.y;
+          if (!select_default2(this).classed("dragging") && // don't display drag until dragging beyond a distance threshold
+          Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2)) <= 5) return;
+          var index = items.nodes().indexOf(this);
+          select_default2(this).classed("dragging", true);
+          targetIndex = null;
+          selection2.selectAll("li.member-row").style("transform", function(d2, index2) {
+            var node = select_default2(this).node();
+            if (index === index2) {
+              return "translate(" + x2 + "px, " + y2 + "px)";
+            } else if (index2 > index && d3_event.y > node.offsetTop) {
+              if (targetIndex === null || index2 > targetIndex) {
+                targetIndex = index2;
+              }
+              return "translateY(-100%)";
+            } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
+              if (targetIndex === null || index2 < targetIndex) {
+                targetIndex = index2;
+              }
+              return "translateY(100%)";
+            }
+            return null;
+          });
+        }).on("end", function(d3_event, d2) {
+          if (!select_default2(this).classed("dragging")) return;
+          var index = items.nodes().indexOf(this);
+          select_default2(this).classed("dragging", false);
+          selection2.selectAll("li.member-row").style("transform", null);
+          if (targetIndex !== null) {
+            context.perform(
+              actionMoveMember(d2.relation.id, index, targetIndex),
+              _t("operations.reorder_members.annotation")
+            );
+            context.validator().validate();
+          }
+        })
       );
-      context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
+      function bindTypeahead(d2) {
+        var row = select_default2(this);
+        var role = row.selectAll("input.member-role");
+        var origValue = role.property("value");
+        function sort(value, data) {
+          var sameletter = [];
+          var other = [];
+          for (var i3 = 0; i3 < data.length; i3++) {
+            if (data[i3].value.substring(0, value.length) === value) {
+              sameletter.push(data[i3]);
+            } else {
+              other.push(data[i3]);
+            }
+          }
+          return sameletter.concat(other);
+        }
+        role.call(
+          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
+            var geometry;
+            if (d2.member) {
+              geometry = context.graph().geometry(d2.member.id);
+            } else if (d2.type === "relation") {
+              geometry = "relation";
+            } else if (d2.type === "way") {
+              geometry = "line";
+            } else {
+              geometry = "point";
+            }
+            var rtype = entity.tags.type;
+            taginfo.roles({
+              debounce: true,
+              rtype: rtype || "",
+              geometry,
+              query: role2
+            }, function(err, data) {
+              if (!err) callback(sort(role2, data));
+            });
+          }).on("cancel", function() {
+            role.property("value", origValue);
+          })
+        );
+      }
+      function unbind() {
+        var row = select_default2(this);
+        row.selectAll("input.member-role").call(uiCombobox.off, context);
+      }
     }
-    mode.enter = function() {
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return section;
     };
-    return mode;
+    return section;
   }
 
-  // modules/modes/add_point.js
-  function modeAddPoint(context, mode) {
-    mode.id = "add-point";
-    var behavior = behaviorDraw(context).on("click", add).on("clickWay", addWay).on("clickNode", addNode).on("cancel", cancel).on("finish", cancel);
-    var defaultTags = {};
-    if (mode.preset)
-      defaultTags = mode.preset.setTags(defaultTags, "point");
-    function add(loc) {
-      var node = osmNode({ loc, tags: defaultTags });
-      context.perform(
-        actionAddEntity(node),
-        _t("operations.add.annotation.point")
-      );
-      enterSelectMode(node);
-    }
-    function addWay(loc, edge) {
-      var node = osmNode({ tags: defaultTags });
-      context.perform(
-        actionAddMidpoint({ loc, edge }, node),
-        _t("operations.add.annotation.vertex")
-      );
-      enterSelectMode(node);
-    }
-    function enterSelectMode(node) {
-      context.enter(
-        modeSelect(context, [node.id]).newFeature(true)
-      );
-    }
-    function addNode(node) {
-      if (Object.keys(defaultTags).length === 0) {
-        enterSelectMode(node);
-        return;
-      }
-      var tags = Object.assign({}, node.tags);
-      for (var key in defaultTags) {
-        tags[key] = defaultTags[key];
+  // modules/actions/delete_members.js
+  function actionDeleteMembers(relationId, memberIndexes) {
+    return function(graph) {
+      memberIndexes.sort((a2, b2) => b2 - a2);
+      for (var i3 in memberIndexes) {
+        graph = actionDeleteMember(relationId, memberIndexes[i3])(graph);
       }
-      context.perform(
-        actionChangeTags(node.id, tags),
-        _t("operations.add.annotation.point")
-      );
-      enterSelectMode(node);
-    }
-    function cancel() {
-      context.enter(modeBrowse(context));
-    }
-    mode.enter = function() {
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
+      return graph;
     };
-    return mode;
   }
 
-  // modules/modes/select_note.js
-  function modeSelectNote(context, selectedNoteID) {
-    var mode = {
-      id: "select-note",
-      button: "browse"
-    };
-    var _keybinding = utilKeybinding("select-note");
-    var _noteEditor = uiNoteEditor(context).on("change", function() {
-      context.map().pan([0, 0]);
-      var note = checkSelectedID();
-      if (!note)
-        return;
-      context.ui().sidebar.show(_noteEditor.note(note));
+  // modules/ui/sections/raw_membership_editor.js
+  function uiSectionRawMembershipEditor(context) {
+    var section = uiSection("raw-membership-editor", context).shouldDisplay(function() {
+      return _entityIDs && _entityIDs.length;
+    }).label(function() {
+      var parents = getSharedParentRelations();
+      var gt2 = parents.length > _maxMemberships ? ">" : "";
+      var count = gt2 + parents.slice(0, _maxMemberships).length;
+      return _t.append("inspector.title_count", { title: _t("inspector.relations"), count });
+    }).disclosureContent(renderDisclosureContent);
+    var taginfo = services.taginfo;
+    var nearbyCombo = uiCombobox(context, "parent-relation").minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function(d3_event, d2) {
+      if (d2.relation) utilHighlightEntities([d2.relation.id], true, context);
+    }).itemsMouseLeave(function(d3_event, d2) {
+      if (d2.relation) utilHighlightEntities([d2.relation.id], false, context);
     });
-    var _behaviors = [
-      behaviorBreathe(context),
-      behaviorHover(context),
-      behaviorSelect(context),
-      behaviorLasso(context),
-      modeDragNode(context).behavior,
-      modeDragNote(context).behavior
-    ];
-    var _newFeature = false;
-    function checkSelectedID() {
-      if (!services.osm)
-        return;
-      var note = services.osm.getNote(selectedNoteID);
-      if (!note) {
-        context.enter(modeBrowse(context));
-      }
-      return note;
-    }
-    function selectNote(d3_event, drawn) {
-      if (!checkSelectedID())
-        return;
-      var selection2 = context.surface().selectAll(".layer-notes .note-" + selectedNoteID);
-      if (selection2.empty()) {
-        var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
-        if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
-          context.enter(modeBrowse(context));
+    var _inChange = false;
+    var _entityIDs = [];
+    var _showBlank;
+    var _maxMemberships = 1e3;
+    function getSharedParentRelations() {
+      var parents = [];
+      for (var i3 = 0; i3 < _entityIDs.length; i3++) {
+        var entity = context.graph().hasEntity(_entityIDs[i3]);
+        if (!entity) continue;
+        if (i3 === 0) {
+          parents = context.graph().parentRelations(entity);
+        } else {
+          parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
         }
-      } else {
-        selection2.classed("selected", true);
-        context.selectedNoteID(selectedNoteID);
+        if (!parents.length) break;
       }
+      return parents;
     }
-    function esc() {
-      if (context.container().select(".combobox").size())
-        return;
-      context.enter(modeBrowse(context));
-    }
-    mode.zoomToSelected = function() {
-      if (!services.osm)
-        return;
-      var note = services.osm.getNote(selectedNoteID);
-      if (note) {
-        context.map().centerZoomEase(note.loc, 20);
+    function getMemberships() {
+      var memberships = [];
+      var relations = getSharedParentRelations().slice(0, _maxMemberships);
+      var isMultiselect = _entityIDs.length > 1;
+      var i3, relation, membership, index, member, indexedMember;
+      for (i3 = 0; i3 < relations.length; i3++) {
+        relation = relations[i3];
+        membership = {
+          relation,
+          members: [],
+          hash: osmEntity.key(relation)
+        };
+        for (index = 0; index < relation.members.length; index++) {
+          member = relation.members[index];
+          if (_entityIDs.indexOf(member.id) !== -1) {
+            indexedMember = Object.assign({}, member, { index });
+            membership.members.push(indexedMember);
+            membership.hash += "," + index.toString();
+            if (!isMultiselect) {
+              memberships.push(membership);
+              membership = {
+                relation,
+                members: [],
+                hash: osmEntity.key(relation)
+              };
+            }
+          }
+        }
+        if (membership.members.length) memberships.push(membership);
       }
-    };
-    mode.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
-      _newFeature = val;
-      return mode;
-    };
-    mode.enter = function() {
-      var note = checkSelectedID();
-      if (!note)
-        return;
-      _behaviors.forEach(context.install);
-      _keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
-      select_default2(document).call(_keybinding);
-      selectNote();
-      var sidebar = context.ui().sidebar;
-      sidebar.show(_noteEditor.note(note).newNote(_newFeature));
-      sidebar.expand(sidebar.intersects(note.extent()));
-      context.map().on("drawn.select", selectNote);
-    };
-    mode.exit = function() {
-      _behaviors.forEach(context.uninstall);
-      select_default2(document).call(_keybinding.unbind);
-      context.surface().selectAll(".layer-notes .selected").classed("selected hover", false);
-      context.map().on("drawn.select", null);
-      context.ui().sidebar.hide();
-      context.selectedNoteID(null);
-    };
-    return mode;
-  }
-
-  // modules/modes/add_note.js
-  function modeAddNote(context) {
-    var mode = {
-      id: "add-note",
-      button: "note",
-      description: _t.append("modes.add_note.description"),
-      key: _t("modes.add_note.key")
-    };
-    var behavior = behaviorDraw(context).on("click", add).on("cancel", cancel).on("finish", cancel);
-    function add(loc) {
-      var osm = services.osm;
-      if (!osm)
-        return;
-      var note = osmNote({ loc, status: "open", comments: [] });
-      osm.replaceNote(note);
-      context.map().pan([0, 0]);
-      context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
-    }
-    function cancel() {
-      context.enter(modeBrowse(context));
-    }
-    mode.enter = function() {
-      context.install(behavior);
-    };
-    mode.exit = function() {
-      context.uninstall(behavior);
-    };
-    return mode;
-  }
-
-  // modules/modes/save.js
-  function modeSave(context) {
-    var mode = { id: "save" };
-    var keybinding = utilKeybinding("modeSave");
-    var commit = uiCommit(context).on("cancel", cancel);
-    var _conflictsUi;
-    var _location;
-    var _success;
-    var uploader = context.uploader().on("saveStarted.modeSave", function() {
-      keybindingOff();
-    }).on("willAttemptUpload.modeSave", prepareForSuccess).on("progressChanged.modeSave", showProgress).on("resultNoChanges.modeSave", function() {
-      cancel();
-    }).on("resultErrors.modeSave", showErrors).on("resultConflicts.modeSave", showConflicts).on("resultSuccess.modeSave", showSuccess);
-    function cancel() {
-      context.enter(modeBrowse(context));
-    }
-    function showProgress(num, total) {
-      var modal = context.container().select(".loading-modal .modal-section");
-      var progress = modal.selectAll(".progress").data([0]);
-      progress.enter().append("div").attr("class", "progress").merge(progress).text(_t("save.conflict_progress", { num, total }));
-    }
-    function showConflicts(changeset, conflicts, origChanges) {
-      var selection2 = context.container().select(".sidebar").append("div").attr("class", "sidebar-component");
-      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
-      _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on("cancel", function() {
-        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
-        selection2.remove();
-        keybindingOn();
-        uploader.cancelConflictResolution();
-      }).on("save", function() {
-        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
-        selection2.remove();
-        uploader.processResolvedConflicts(changeset);
+      memberships.forEach(function(membership2) {
+        membership2.domId = utilUniqueDomId("membership-" + membership2.relation.id);
+        var roles = [];
+        membership2.members.forEach(function(member2) {
+          if (roles.indexOf(member2.role) === -1) roles.push(member2.role);
+        });
+        membership2.role = roles.length === 1 ? roles[0] : roles;
       });
-      selection2.call(_conflictsUi);
+      return memberships;
     }
-    function showErrors(errors) {
-      keybindingOn();
-      var selection2 = uiConfirm(context.container());
-      selection2.select(".modal-section.header").append("h3").text(_t("save.error"));
-      addErrors(selection2, errors);
-      selection2.okButton();
+    function selectRelation(d3_event, d2) {
+      d3_event.preventDefault();
+      utilHighlightEntities([d2.relation.id], false, context);
+      context.enter(modeSelect(context, [d2.relation.id]));
     }
-    function addErrors(selection2, data) {
-      var message = selection2.select(".modal-section.message-text");
-      var items = message.selectAll(".error-container").data(data);
-      var enter = items.enter().append("div").attr("class", "error-container");
-      enter.append("a").attr("class", "error-description").attr("href", "#").classed("hide-toggle", true).text(function(d) {
-        return d.msg || _t("save.unknown_error_details");
-      }).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        var error = select_default2(this);
-        var detail = select_default2(this.nextElementSibling);
-        var exp2 = error.classed("expanded");
-        detail.style("display", exp2 ? "none" : "block");
-        error.classed("expanded", !exp2);
-      });
-      var details = enter.append("div").attr("class", "error-detail-container").style("display", "none");
-      details.append("ul").attr("class", "error-detail-list").selectAll("li").data(function(d) {
-        return d.details || [];
-      }).enter().append("li").attr("class", "error-detail-item").text(function(d) {
-        return d;
-      });
-      items.exit().remove();
+    function zoomToRelation(d3_event, d2) {
+      d3_event.preventDefault();
+      var entity = context.entity(d2.relation.id);
+      context.map().zoomToEase(entity);
+      utilHighlightEntities([d2.relation.id], true, context);
     }
-    function showSuccess(changeset) {
-      commit.reset();
-      var ui = _success.changeset(changeset).location(_location).on("cancel", function() {
-        context.ui().sidebar.hide();
+    function changeRole(d3_event, d2) {
+      if (d2 === 0) return;
+      if (_inChange) return;
+      var newRole = context.cleanRelationRole(select_default2(this).property("value"));
+      if (!newRole.trim() && typeof d2.role !== "string") return;
+      var membersToUpdate = d2.members.filter(function(member) {
+        return member.role !== newRole;
       });
-      context.enter(modeBrowse(context).sidebar(ui));
+      if (membersToUpdate.length) {
+        _inChange = true;
+        context.perform(
+          function actionChangeMemberRoles(graph) {
+            membersToUpdate.forEach(function(member) {
+              var newMember = Object.assign({}, member, { role: newRole });
+              delete newMember.index;
+              graph = actionChangeMember(d2.relation.id, newMember, member.index)(graph);
+            });
+            return graph;
+          },
+          _t("operations.change_role.annotation", {
+            n: membersToUpdate.length
+          })
+        );
+        context.validator().validate();
+      }
+      _inChange = false;
     }
-    function keybindingOn() {
-      select_default2(document).call(keybinding.on("\u238B", cancel, true));
+    function addMembership(d2, role) {
+      this.blur();
+      _showBlank = false;
+      function actionAddMembers(relationId, ids, role2) {
+        return function(graph) {
+          for (var i3 in ids) {
+            var member = { id: ids[i3], type: graph.entity(ids[i3]).type, role: role2 };
+            graph = actionAddMember(relationId, member)(graph);
+          }
+          return graph;
+        };
+      }
+      if (d2.relation) {
+        context.perform(
+          actionAddMembers(d2.relation.id, _entityIDs, role),
+          _t("operations.add_member.annotation", {
+            n: _entityIDs.length
+          })
+        );
+        context.validator().validate();
+      } else {
+        var relation = osmRelation();
+        context.perform(
+          actionAddEntity(relation),
+          actionAddMembers(relation.id, _entityIDs, role),
+          _t("operations.add.annotation.relation")
+        );
+        context.enter(modeSelect(context, [relation.id]).newFeature(true));
+      }
     }
-    function keybindingOff() {
-      select_default2(document).call(keybinding.unbind);
+    function downloadMembers(d3_event, d2) {
+      d3_event.preventDefault();
+      const button = select_default2(this);
+      button.classed("loading", true);
+      context.loadEntity(d2.relation.id, function() {
+        section.reRender();
+      });
     }
-    function prepareForSuccess() {
-      _success = uiSuccess(context);
-      _location = null;
-      if (!services.geocoder)
-        return;
-      services.geocoder.reverse(context.map().center(), function(err, result) {
-        if (err || !result || !result.address)
-          return;
-        var addr = result.address;
-        var place = addr && (addr.town || addr.city || addr.county) || "";
-        var region = addr && (addr.state || addr.country) || "";
-        var separator = place && region ? _t("success.thank_you_where.separator") : "";
-        _location = _t(
-          "success.thank_you_where.format",
-          { place, separator, region }
-        );
+    function deleteMembership(d3_event, d2) {
+      this.blur();
+      if (d2 === 0) return;
+      utilHighlightEntities([d2.relation.id], false, context);
+      var indexes = d2.members.map(function(member) {
+        return member.index;
       });
+      context.perform(
+        actionDeleteMembers(d2.relation.id, indexes),
+        _t("operations.delete_member.annotation", {
+          n: _entityIDs.length
+        })
+      );
+      context.validator().validate();
     }
-    mode.selectedIDs = function() {
-      return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
-    };
-    mode.enter = function() {
-      context.ui().sidebar.expand();
-      function done() {
-        context.ui().sidebar.show(commit);
+    function fetchNearbyRelations(q2, callback) {
+      var newRelation = {
+        relation: null,
+        value: _t("inspector.new_relation"),
+        display: _t.append("inspector.new_relation")
+      };
+      var entityID = _entityIDs[0];
+      var result = [];
+      var graph = context.graph();
+      function baseDisplayValue(entity) {
+        var matched = _mainPresetIndex.match(entity, graph);
+        var presetName = matched && matched.name() || _t("inspector.relation");
+        var entityName = utilDisplayName(entity) || "";
+        return presetName + " " + entityName;
       }
-      keybindingOn();
-      context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
-      var osm = context.connection();
-      if (!osm) {
-        cancel();
-        return;
+      function baseDisplayLabel(entity) {
+        var matched = _mainPresetIndex.match(entity, graph);
+        var presetName = matched && matched.name() || _t("inspector.relation");
+        var entityName = utilDisplayName(entity) || "";
+        return (selection2) => {
+          selection2.append("b").text(presetName + " ");
+          selection2.append("span").classed("has-colour", entity.tags.colour && isColourValid(entity.tags.colour)).style("border-color", entity.tags.colour).text(entityName);
+        };
       }
-      if (osm.authenticated()) {
-        done();
+      var explicitRelation = q2 && context.hasEntity(q2.toLowerCase());
+      if (explicitRelation && explicitRelation.type === "relation" && explicitRelation.id !== entityID) {
+        result.push({
+          relation: explicitRelation,
+          value: baseDisplayValue(explicitRelation) + " " + explicitRelation.id,
+          display: baseDisplayLabel(explicitRelation)
+        });
       } else {
-        osm.authenticate(function(err) {
-          if (err) {
-            cancel();
-          } else {
-            done();
-          }
+        context.history().intersects(context.map().extent()).forEach(function(entity) {
+          if (entity.type !== "relation" || entity.id === entityID) return;
+          var value = baseDisplayValue(entity);
+          if (q2 && (value + " " + entity.id).toLowerCase().indexOf(q2.toLowerCase()) === -1) return;
+          result.push({
+            relation: entity,
+            value,
+            display: baseDisplayLabel(entity)
+          });
         });
-      }
-    };
-    mode.exit = function() {
-      keybindingOff();
-      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
-      context.ui().sidebar.hide();
-    };
-    return mode;
-  }
-
-  // modules/modes/select_error.js
-  function modeSelectError(context, selectedErrorID, selectedErrorService) {
-    var mode = {
-      id: "select-error",
-      button: "browse"
-    };
-    var keybinding = utilKeybinding("select-error");
-    var errorService = services[selectedErrorService];
-    var errorEditor;
-    switch (selectedErrorService) {
-      case "improveOSM":
-        errorEditor = uiImproveOsmEditor(context).on("change", function() {
-          context.map().pan([0, 0]);
-          var error = checkSelectedID();
-          if (!error)
-            return;
-          context.ui().sidebar.show(errorEditor.error(error));
+        result.sort(function(a2, b2) {
+          return osmRelation.creationOrder(a2.relation, b2.relation);
         });
-        break;
-      case "keepRight":
-        errorEditor = uiKeepRightEditor(context).on("change", function() {
-          context.map().pan([0, 0]);
-          var error = checkSelectedID();
-          if (!error)
-            return;
-          context.ui().sidebar.show(errorEditor.error(error));
+        var dupeGroups = Object.values(utilArrayGroupBy(result, "value")).filter(function(v2) {
+          return v2.length > 1;
         });
-        break;
-      case "osmose":
-        errorEditor = uiOsmoseEditor(context).on("change", function() {
-          context.map().pan([0, 0]);
-          var error = checkSelectedID();
-          if (!error)
-            return;
-          context.ui().sidebar.show(errorEditor.error(error));
+        dupeGroups.forEach(function(group) {
+          group.forEach(function(obj) {
+            obj.value += " " + obj.relation.id;
+          });
         });
-        break;
-    }
-    var behaviors = [
-      behaviorBreathe(context),
-      behaviorHover(context),
-      behaviorSelect(context),
-      behaviorLasso(context),
-      modeDragNode(context).behavior,
-      modeDragNote(context).behavior
-    ];
-    function checkSelectedID() {
-      if (!errorService)
-        return;
-      var error = errorService.getError(selectedErrorID);
-      if (!error) {
-        context.enter(modeBrowse(context));
       }
-      return error;
+      result.forEach(function(obj) {
+        obj.title = obj.value;
+      });
+      result.unshift(newRelation);
+      callback(result);
     }
-    mode.zoomToSelected = function() {
-      if (!errorService)
-        return;
-      var error = errorService.getError(selectedErrorID);
-      if (error) {
-        context.map().centerZoomEase(error.loc, 20);
+    function renderDisclosureContent(selection2) {
+      var memberships = getMemberships();
+      var list2 = selection2.selectAll(".member-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "member-list").merge(list2);
+      var items = list2.selectAll("li.member-row-normal").data(memberships, function(d2) {
+        return d2.hash;
+      });
+      items.exit().each(unbind).remove();
+      var itemsEnter = items.enter().append("li").attr("class", "member-row member-row-normal form-field");
+      itemsEnter.on("mouseover", function(d3_event, d2) {
+        utilHighlightEntities([d2.relation.id], true, context);
+      }).on("mouseout", function(d3_event, d2) {
+        utilHighlightEntities([d2.relation.id], false, context);
+      });
+      var labelEnter = itemsEnter.append("label").attr("class", "field-label").attr("for", function(d2) {
+        return d2.domId;
+      });
+      var labelLink = labelEnter.append("span").attr("class", "label-text").append("a").attr("href", "#").on("click", selectRelation);
+      labelLink.append("span").attr("class", "member-entity-type").text(function(d2) {
+        var matched = _mainPresetIndex.match(d2.relation, context.graph());
+        return matched && matched.name() || _t.html("inspector.relation");
+      });
+      labelLink.append("span").attr("class", "member-entity-name").classed("has-colour", (d2) => d2.relation.tags.colour && isColourValid(d2.relation.tags.colour)).style("border-color", (d2) => d2.relation.tags.colour).text(function(d2) {
+        return utilDisplayName(d2.relation);
+      });
+      labelEnter.append("button").attr("class", "members-download").attr("title", _t("icons.download")).call(svgIcon("#iD-icon-load")).on("click", downloadMembers);
+      labelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", deleteMembership);
+      labelEnter.append("button").attr("class", "member-zoom").attr("title", _t("icons.zoom_to")).call(svgIcon("#iD-icon-framed-dot", "monochrome")).on("click", zoomToRelation);
+      items = items.merge(itemsEnter);
+      items.selectAll("button.members-download").classed("hide", (d2) => {
+        const graph = context.graph();
+        return d2.relation.members.every((m2) => graph.hasEntity(m2.id));
+      });
+      var wrapEnter = itemsEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
+      wrapEnter.append("input").attr("class", "member-role").attr("id", function(d2) {
+        return d2.domId;
+      }).property("type", "text").property("value", function(d2) {
+        return typeof d2.role === "string" ? d2.role : "";
+      }).attr("title", function(d2) {
+        return Array.isArray(d2.role) ? d2.role.filter(Boolean).join("\n") : d2.role;
+      }).attr("placeholder", function(d2) {
+        return Array.isArray(d2.role) ? _t("inspector.multiple_roles") : _t("inspector.role");
+      }).classed("mixed", function(d2) {
+        return Array.isArray(d2.role);
+      }).call(utilNoAuto).on("blur", changeRole).on("change", changeRole);
+      if (taginfo) {
+        wrapEnter.each(bindTypeahead);
       }
-    };
-    mode.enter = function() {
-      var error = checkSelectedID();
-      if (!error)
-        return;
-      behaviors.forEach(context.install);
-      keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
-      select_default2(document).call(keybinding);
-      selectError();
-      var sidebar = context.ui().sidebar;
-      sidebar.show(errorEditor.error(error));
-      context.map().on("drawn.select-error", selectError);
-      function selectError(d3_event, drawn) {
-        if (!checkSelectedID())
+      var newMembership = list2.selectAll(".member-row-new").data(_showBlank ? [0] : []);
+      newMembership.exit().remove();
+      var newMembershipEnter = newMembership.enter().append("li").attr("class", "member-row member-row-new form-field");
+      var newLabelEnter = newMembershipEnter.append("label").attr("class", "field-label");
+      newLabelEnter.append("input").attr("placeholder", _t("inspector.choose_relation")).attr("type", "text").attr("class", "member-entity-input").call(utilNoAuto);
+      newLabelEnter.append("button").attr("class", "remove member-delete").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete")).on("click", function() {
+        list2.selectAll(".member-row-new").remove();
+      });
+      var newWrapEnter = newMembershipEnter.append("div").attr("class", "form-field-input-wrap form-field-input-member");
+      newWrapEnter.append("input").attr("class", "member-role").property("type", "text").attr("placeholder", _t("inspector.role")).call(utilNoAuto);
+      newMembership = newMembership.merge(newMembershipEnter);
+      newMembership.selectAll(".member-entity-input").on("blur", cancelEntity).call(
+        nearbyCombo.on("accept", acceptEntity).on("cancel", cancelEntity)
+      );
+      var addRow = selection2.selectAll(".add-row").data([0]);
+      var addRowEnter = addRow.enter().append("div").attr("class", "add-row");
+      var addRelationButton = addRowEnter.append("button").attr("class", "add-relation").attr("aria-label", _t("inspector.add_to_relation"));
+      addRelationButton.call(svgIcon("#iD-icon-plus", "light"));
+      addRelationButton.call(uiTooltip().title(() => _t.append("inspector.add_to_relation")).placement(_mainLocalizer.textDirection() === "ltr" ? "right" : "left"));
+      addRowEnter.append("div").attr("class", "space-value");
+      addRowEnter.append("div").attr("class", "space-buttons");
+      addRow = addRow.merge(addRowEnter);
+      addRow.select(".add-relation").on("click", function() {
+        _showBlank = true;
+        section.reRender();
+        list2.selectAll(".member-entity-input").node().focus();
+      });
+      function acceptEntity(d2) {
+        if (!d2) {
+          cancelEntity();
           return;
-        var selection2 = context.surface().selectAll(".itemId-" + selectedErrorID + "." + selectedErrorService);
-        if (selection2.empty()) {
-          var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
-          if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
-            context.enter(modeBrowse(context));
-          }
-        } else {
-          selection2.classed("selected", true);
-          context.selectedErrorID(selectedErrorID);
         }
+        if (d2.relation) utilHighlightEntities([d2.relation.id], false, context);
+        var role = context.cleanRelationRole(list2.selectAll(".member-row-new .member-role").property("value"));
+        addMembership(d2, role);
       }
-      function esc() {
-        if (context.container().select(".combobox").size())
-          return;
-        context.enter(modeBrowse(context));
+      function cancelEntity() {
+        var input = newMembership.selectAll(".member-entity-input");
+        input.property("value", "");
+        context.surface().selectAll(".highlighted").classed("highlighted", false);
       }
-    };
-    mode.exit = function() {
-      behaviors.forEach(context.uninstall);
-      select_default2(document).call(keybinding.unbind);
-      context.surface().selectAll(".qaItem.selected").classed("selected hover", false);
-      context.map().on("drawn.select-error", null);
-      context.ui().sidebar.hide();
-      context.selectedErrorID(null);
-      context.features().forceVisible([]);
-    };
-    return mode;
-  }
-
-  // modules/ui/tools/modes.js
-  function uiToolDrawModes(context) {
-    var tool = {
-      id: "old_modes",
-      label: _t.append("toolbar.add_feature")
-    };
-    var modes = [
-      modeAddPoint(context, {
-        title: _t.append("modes.add_point.title"),
-        button: "point",
-        description: _t.append("modes.add_point.description"),
-        preset: _mainPresetIndex.item("point"),
-        key: "1"
-      }),
-      modeAddLine(context, {
-        title: _t.append("modes.add_line.title"),
-        button: "line",
-        description: _t.append("modes.add_line.description"),
-        preset: _mainPresetIndex.item("line"),
-        key: "2"
-      }),
-      modeAddArea(context, {
-        title: _t.append("modes.add_area.title"),
-        button: "area",
-        description: _t.append("modes.add_area.description"),
-        preset: _mainPresetIndex.item("area"),
-        key: "3"
-      })
-    ];
-    function enabled(_mode) {
-      return osmEditable();
-    }
-    function osmEditable() {
-      return context.editable();
-    }
-    modes.forEach(function(mode) {
-      context.keybinding().on(mode.key, function() {
-        if (!enabled(mode))
-          return;
-        if (mode.id === context.mode().id) {
-          context.enter(modeBrowse(context));
-        } else {
-          context.enter(mode);
-        }
-      });
-    });
-    tool.render = function(selection2) {
-      var wrap2 = selection2.append("div").attr("class", "joined").style("display", "flex");
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.map().on("move.modes", debouncedUpdate).on("drawn.modes", debouncedUpdate);
-      context.on("enter.modes", update);
-      update();
-      function update() {
-        var buttons = wrap2.selectAll("button.add-button").data(modes, function(d) {
-          return d.id;
-        });
-        buttons.exit().remove();
-        var buttonsEnter = buttons.enter().append("button").attr("class", function(d) {
-          return d.id + " add-button bar-button";
-        }).on("click.mode-buttons", function(d3_event, d) {
-          if (!enabled(d))
-            return;
-          var currMode = context.mode().id;
-          if (/^draw/.test(currMode))
-            return;
-          if (d.id === currMode) {
-            context.enter(modeBrowse(context));
-          } else {
-            context.enter(d);
+      function bindTypeahead(d2) {
+        var row = select_default2(this);
+        var role = row.selectAll("input.member-role");
+        var origValue = role.property("value");
+        function sort(value, data) {
+          var sameletter = [];
+          var other = [];
+          for (var i3 = 0; i3 < data.length; i3++) {
+            if (data[i3].value.substring(0, value.length) === value) {
+              sameletter.push(data[i3]);
+            } else {
+              other.push(data[i3]);
+            }
           }
-        }).call(
-          uiTooltip().placement("bottom").title(function(d) {
-            return d.description;
-          }).keys(function(d) {
-            return [d.key];
-          }).scrollContainer(context.container().select(".top-toolbar"))
-        );
-        buttonsEnter.each(function(d) {
-          select_default2(this).call(svgIcon("#iD-icon-" + d.button));
-        });
-        buttonsEnter.append("span").attr("class", "label").text("").each(function(mode) {
-          mode.title(select_default2(this));
-        });
-        if (buttons.enter().size() || buttons.exit().size()) {
-          context.ui().checkOverflow(".top-toolbar", true);
+          return sameletter.concat(other);
         }
-        buttons = buttons.merge(buttonsEnter).attr("aria-disabled", function(d) {
-          return !enabled(d);
-        }).classed("disabled", function(d) {
-          return !enabled(d);
-        }).attr("aria-pressed", function(d) {
-          return context.mode() && context.mode().button === d.button;
-        }).classed("active", function(d) {
-          return context.mode() && context.mode().button === d.button;
-        });
+        role.call(
+          uiCombobox(context, "member-role").fetcher(function(role2, callback) {
+            var rtype = d2.relation.tags.type;
+            taginfo.roles({
+              debounce: true,
+              rtype: rtype || "",
+              geometry: context.graph().geometry(_entityIDs[0]),
+              query: role2
+            }, function(err, data) {
+              if (!err) callback(sort(role2, data));
+            });
+          }).on("cancel", function() {
+            role.property("value", origValue);
+          })
+        );
+      }
+      function unbind() {
+        var row = select_default2(this);
+        row.selectAll("input.member-role").call(uiCombobox.off, context);
       }
+    }
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _showBlank = false;
+      return section;
     };
-    return tool;
+    return section;
   }
 
-  // modules/ui/tools/notes.js
-  function uiToolNotes(context) {
-    var tool = {
-      id: "notes",
-      label: _t.append("modes.add_note.label")
+  // modules/ui/sections/selection_list.js
+  function uiSectionSelectionList(context) {
+    var _selectedIDs = [];
+    var section = uiSection("selected-features", context).shouldDisplay(function() {
+      return _selectedIDs.length > 1;
+    }).label(function() {
+      return _t.append("inspector.title_count", { title: _t("inspector.features"), count: _selectedIDs.length });
+    }).disclosureContent(renderDisclosureContent);
+    context.history().on("change.selectionList", function(difference2) {
+      if (difference2) {
+        section.reRender();
+      }
+    });
+    section.entityIDs = function(val) {
+      if (!arguments.length) return _selectedIDs;
+      _selectedIDs = val;
+      return section;
     };
-    var mode = modeAddNote(context);
-    function enabled() {
-      return notesEnabled() && notesEditable();
+    function selectEntity(d3_event, entity) {
+      context.enter(modeSelect(context, [entity.id]));
     }
-    function notesEnabled() {
-      var noteLayer = context.layers().layer("notes");
-      return noteLayer && noteLayer.enabled();
+    function deselectEntity(d3_event, entity) {
+      var selectedIDs = _selectedIDs.slice();
+      var index = selectedIDs.indexOf(entity.id);
+      if (index > -1) {
+        selectedIDs.splice(index, 1);
+        context.enter(modeSelect(context, selectedIDs));
+      }
     }
-    function notesEditable() {
-      var mode2 = context.mode();
-      return context.map().notesEditable() && mode2 && mode2.id !== "save";
+    function renderDisclosureContent(selection2) {
+      var list2 = selection2.selectAll(".feature-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "feature-list").merge(list2);
+      var entities = _selectedIDs.map(function(id2) {
+        return context.hasEntity(id2);
+      }).filter(Boolean);
+      var items = list2.selectAll(".feature-list-item").data(entities, osmEntity.key);
+      items.exit().remove();
+      var enter = items.enter().append("li").attr("class", "feature-list-item").each(function(d2) {
+        select_default2(this).on("mouseover", function() {
+          utilHighlightEntities([d2.id], true, context);
+        }).on("mouseout", function() {
+          utilHighlightEntities([d2.id], false, context);
+        });
+      });
+      var label = enter.append("button").attr("class", "label").on("click", selectEntity);
+      label.append("span").attr("class", "entity-geom-icon").call(svgIcon("", "pre-text"));
+      label.append("span").attr("class", "entity-type");
+      label.append("span").attr("class", "entity-name");
+      enter.append("button").attr("class", "close").attr("title", _t("icons.deselect")).on("click", deselectEntity).call(svgIcon("#iD-icon-close"));
+      items = items.merge(enter);
+      items.selectAll(".entity-geom-icon use").attr("href", function() {
+        var entity = this.parentNode.parentNode.__data__;
+        return "#iD-icon-" + entity.geometry(context.graph());
+      });
+      items.selectAll(".entity-type").text(function(entity) {
+        return _mainPresetIndex.match(entity, context.graph()).name();
+      });
+      items.selectAll(".entity-name").text(function(d2) {
+        var entity = context.entity(d2.id);
+        return utilDisplayName(entity);
+      });
     }
-    context.keybinding().on(mode.key, function() {
-      if (!enabled())
-        return;
-      if (mode.id === context.mode().id) {
+    return section;
+  }
+
+  // modules/ui/entity_editor.js
+  function uiEntityEditor(context) {
+    var dispatch14 = dispatch_default("choose");
+    var _state = "select";
+    var _coalesceChanges = false;
+    var _modified = false;
+    var _base;
+    var _entityIDs;
+    var _activePresets = [];
+    var _newFeature;
+    var _sections;
+    function entityEditor(selection2) {
+      var combinedTags = utilCombinedTags(_entityIDs, context.graph());
+      var header = selection2.selectAll(".header").data([0]);
+      var headerEnter = header.enter().append("div").attr("class", "header fillL");
+      var direction = _mainLocalizer.textDirection() === "rtl" ? "forward" : "backward";
+      headerEnter.append("button").attr("class", "preset-reset preset-choose").attr("title", _t("inspector.back_tooltip")).call(svgIcon("#iD-icon-".concat(direction)));
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
         context.enter(modeBrowse(context));
-      } else {
-        context.enter(mode);
+      }).call(svgIcon(_modified ? "#iD-icon-apply" : "#iD-icon-close"));
+      headerEnter.append("h2");
+      header = header.merge(headerEnter);
+      header.selectAll("h2").text("").call(_entityIDs.length === 1 ? _t.append("inspector.edit") : _t.append("inspector.edit_features"));
+      header.selectAll(".preset-reset").on("click", function() {
+        dispatch14.call("choose", this, _activePresets);
+      });
+      var body = selection2.selectAll(".inspector-body").data([0]);
+      var bodyEnter = body.enter().append("div").attr("class", "entity-editor inspector-body sep-top");
+      body = body.merge(bodyEnter);
+      if (!_sections) {
+        _sections = [
+          uiSectionSelectionList(context),
+          uiSectionFeatureType(context).on("choose", function(presets) {
+            dispatch14.call("choose", this, presets);
+          }),
+          uiSectionEntityIssues(context),
+          uiSectionPresetFields(context).on("change", changeTags).on("revert", revertTags),
+          uiSectionRawTagEditor("raw-tag-editor", context).on("change", changeTags),
+          uiSectionRawMemberEditor(context),
+          uiSectionRawMembershipEditor(context)
+        ];
       }
-    });
-    tool.render = function(selection2) {
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.map().on("move.notes", debouncedUpdate).on("drawn.notes", debouncedUpdate);
-      context.on("enter.notes", update);
-      update();
-      function update() {
-        var showNotes = notesEnabled();
-        var data = showNotes ? [mode] : [];
-        var buttons = selection2.selectAll("button.add-button").data(data, function(d) {
-          return d.id;
-        });
-        buttons.exit().remove();
-        var buttonsEnter = buttons.enter().append("button").attr("class", function(d) {
-          return d.id + " add-button bar-button";
-        }).on("click.notes", function(d3_event, d) {
-          if (!enabled())
-            return;
-          var currMode = context.mode().id;
-          if (/^draw/.test(currMode))
-            return;
-          if (d.id === currMode) {
-            context.enter(modeBrowse(context));
-          } else {
-            context.enter(d);
-          }
-        }).call(
-          uiTooltip().placement("bottom").title(function(d) {
-            return d.description;
-          }).keys(function(d) {
-            return [d.key];
-          }).scrollContainer(context.container().select(".top-toolbar"))
-        );
-        buttonsEnter.each(function(d) {
-          select_default2(this).call(svgIcon(d.icon || "#iD-icon-" + d.button));
-        });
-        if (buttons.enter().size() || buttons.exit().size()) {
-          context.ui().checkOverflow(".top-toolbar", true);
+      _sections.forEach(function(section) {
+        if (section.entityIDs) {
+          section.entityIDs(_entityIDs);
+        }
+        if (section.presets) {
+          section.presets(_activePresets);
+        }
+        if (section.tags) {
+          section.tags(combinedTags);
+        }
+        if (section.state) {
+          section.state(_state);
+        }
+        body.call(section.render);
+      });
+      context.history().on("change.entity-editor", historyChanged);
+      function historyChanged(difference2) {
+        if (selection2.selectAll(".entity-editor").empty()) return;
+        if (_state === "hide") return;
+        var significant = !difference2 || difference2.didChange.properties || difference2.didChange.addition || difference2.didChange.deletion;
+        if (!significant) return;
+        _entityIDs = _entityIDs.filter(context.hasEntity);
+        if (!_entityIDs.length) return;
+        var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
+        loadActivePresets();
+        var graph = context.graph();
+        entityEditor.modified(_base !== graph);
+        entityEditor(selection2);
+        if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
+          context.container().selectAll(".entity-editor button.preset-reset .label").style("background-color", "#fff").transition().duration(750).style("background-color", null);
         }
-        buttons = buttons.merge(buttonsEnter).classed("disabled", function() {
-          return !enabled();
-        }).attr("aria-disabled", function() {
-          return !enabled();
-        }).classed("active", function(d) {
-          return context.mode() && context.mode().button === d.button;
-        }).attr("aria-pressed", function(d) {
-          return context.mode() && context.mode().button === d.button;
-        });
-      }
-    };
-    tool.uninstall = function() {
-      context.on("enter.editor.notes", null).on("exit.editor.notes", null).on("enter.notes", null);
-      context.map().on("move.notes", null).on("drawn.notes", null);
-    };
-    return tool;
-  }
-
-  // modules/ui/tools/save.js
-  function uiToolSave(context) {
-    var tool = {
-      id: "save",
-      label: _t.append("save.title")
-    };
-    var button = null;
-    var tooltipBehavior = null;
-    var history = context.history();
-    var key = uiCmd("\u2318S");
-    var _numChanges = 0;
-    function isSaving() {
-      var mode = context.mode();
-      return mode && mode.id === "save";
-    }
-    function isDisabled() {
-      return _numChanges === 0 || isSaving();
-    }
-    function save(d3_event) {
-      d3_event.preventDefault();
-      if (!context.inIntro() && !isSaving() && history.hasChanges()) {
-        context.enter(modeSave(context));
       }
     }
-    function bgColor(numChanges) {
-      var step;
-      if (numChanges === 0) {
-        return null;
-      } else if (numChanges <= 50) {
-        step = numChanges / 50;
-        return rgb_default("#fff", "#ff8")(step);
-      } else {
-        step = Math.min((numChanges - 50) / 50, 1);
-        return rgb_default("#ff8", "#f88")(step);
+    function changeTags(entityIDs, changed, onInput) {
+      var actions = [];
+      for (var i3 in entityIDs) {
+        var entityID = entityIDs[i3];
+        var entity = context.entity(entityID);
+        var tags = Object.assign({}, entity.tags);
+        if (typeof changed === "function") {
+          tags = changed(tags);
+        } else {
+          for (var k2 in changed) {
+            if (!k2) continue;
+            var v2 = changed[k2];
+            if (typeof v2 === "object") {
+              tags[k2] = tags[v2.oldKey];
+            } else if (v2 !== void 0 || tags.hasOwnProperty(k2)) {
+              tags[k2] = v2;
+            }
+          }
+        }
+        if (!onInput) {
+          tags = utilCleanTags(tags);
+        }
+        if (!(0, import_fast_deep_equal9.default)(entity.tags, tags)) {
+          actions.push(actionChangeTags(entityID, tags));
+        }
       }
-    }
-    function updateCount() {
-      var val = history.difference().summary().length;
-      if (val === _numChanges)
-        return;
-      _numChanges = val;
-      if (tooltipBehavior) {
-        tooltipBehavior.title(() => _t.append(_numChanges > 0 ? "save.help" : "save.no_changes")).keys([key]);
+      if (actions.length) {
+        var combinedAction = function(graph) {
+          actions.forEach(function(action) {
+            graph = action(graph);
+          });
+          return graph;
+        };
+        var annotation = _t("operations.change_tags.annotation");
+        if (_coalesceChanges) {
+          context.overwrite(combinedAction, annotation);
+        } else {
+          context.perform(combinedAction, annotation);
+          _coalesceChanges = !!onInput;
+        }
       }
-      if (button) {
-        button.classed("disabled", isDisabled()).style("background", bgColor(_numChanges));
-        button.select("span.count").text(_numChanges);
+      if (!onInput) {
+        context.validator().validate();
       }
     }
-    tool.render = function(selection2) {
-      tooltipBehavior = uiTooltip().placement("bottom").title(() => _t.append("save.no_changes")).keys([key]).scrollContainer(context.container().select(".top-toolbar"));
-      var lastPointerUpType;
-      button = selection2.append("button").attr("class", "save disabled bar-button").on("pointerup", function(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
-      }).on("click", function(d3_event) {
-        save(d3_event);
-        if (_numChanges === 0 && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
-          context.ui().flash.duration(2e3).iconName("#iD-icon-save").iconClass("disabled").label(_t.append("save.no_changes"))();
+    function revertTags(keys2) {
+      var actions = [];
+      for (var i3 in _entityIDs) {
+        var entityID = _entityIDs[i3];
+        var original = context.graph().base().entities[entityID];
+        var changed = {};
+        for (var j2 in keys2) {
+          var key = keys2[j2];
+          changed[key] = original ? original.tags[key] : void 0;
         }
-        lastPointerUpType = null;
-      }).call(tooltipBehavior);
-      button.call(svgIcon("#iD-icon-save"));
-      button.append("span").attr("class", "count").attr("aria-hidden", "true").text("0");
-      updateCount();
-      context.keybinding().on(key, save, true);
-      context.history().on("change.save", updateCount);
-      context.on("enter.save", function() {
-        if (button) {
-          button.classed("disabled", isDisabled());
-          if (isSaving()) {
-            button.call(tooltipBehavior.hide);
+        var entity = context.entity(entityID);
+        var tags = Object.assign({}, entity.tags);
+        for (var k2 in changed) {
+          if (!k2) continue;
+          var v2 = changed[k2];
+          if (v2 !== void 0 || tags.hasOwnProperty(k2)) {
+            tags[k2] = v2;
           }
         }
-      });
+        tags = utilCleanTags(tags);
+        if (!(0, import_fast_deep_equal9.default)(entity.tags, tags)) {
+          actions.push(actionChangeTags(entityID, tags));
+        }
+      }
+      if (actions.length) {
+        var combinedAction = function(graph) {
+          actions.forEach(function(action) {
+            graph = action(graph);
+          });
+          return graph;
+        };
+        var annotation = _t("operations.change_tags.annotation");
+        if (_coalesceChanges) {
+          context.overwrite(combinedAction, annotation);
+        } else {
+          context.perform(combinedAction, annotation);
+          _coalesceChanges = false;
+        }
+      }
+      context.validator().validate();
+    }
+    entityEditor.modified = function(val) {
+      if (!arguments.length) return _modified;
+      _modified = val;
+      return entityEditor;
     };
-    tool.uninstall = function() {
-      context.keybinding().off(key, true);
-      context.history().on("change.save", null);
-      context.on("enter.save", null);
-      button = null;
-      tooltipBehavior = null;
+    entityEditor.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      return entityEditor;
     };
-    return tool;
-  }
-
-  // modules/ui/tools/sidebar_toggle.js
-  function uiToolSidebarToggle(context) {
-    var tool = {
-      id: "sidebar_toggle",
-      label: _t.append("toolbar.inspect")
+    entityEditor.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _base = context.graph();
+      _coalesceChanges = false;
+      if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor;
+      _entityIDs = val;
+      loadActivePresets(true);
+      return entityEditor.modified(false);
     };
-    tool.render = function(selection2) {
-      selection2.append("button").attr("class", "bar-button").attr("aria-label", _t("sidebar.tooltip")).on("click", function() {
-        context.ui().sidebar.toggle();
-      }).call(
-        uiTooltip().placement("bottom").title(() => _t.append("sidebar.tooltip")).keys([_t("sidebar.key")]).scrollContainer(context.container().select(".top-toolbar"))
-      ).call(svgIcon("#iD-icon-sidebar-" + (_mainLocalizer.textDirection() === "rtl" ? "right" : "left")));
+    entityEditor.newFeature = function(val) {
+      if (!arguments.length) return _newFeature;
+      _newFeature = val;
+      return entityEditor;
     };
-    return tool;
+    function loadActivePresets(isForNewSelection) {
+      var graph = context.graph();
+      var counts = {};
+      for (var i3 in _entityIDs) {
+        var entity = graph.hasEntity(_entityIDs[i3]);
+        if (!entity) return;
+        var match = _mainPresetIndex.match(entity, graph);
+        if (!counts[match.id]) counts[match.id] = 0;
+        counts[match.id] += 1;
+      }
+      var matches = Object.keys(counts).sort(function(p1, p2) {
+        return counts[p2] - counts[p1];
+      }).map(function(pID) {
+        return _mainPresetIndex.item(pID);
+      });
+      if (!isForNewSelection) {
+        var weakPreset = _activePresets.length === 1 && !_activePresets[0].isFallback() && Object.keys(_activePresets[0].addTags || {}).length === 0;
+        if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
+      }
+      entityEditor.presets(matches);
+    }
+    entityEditor.presets = function(val) {
+      if (!arguments.length) return _activePresets;
+      if (!utilArrayIdentical(val, _activePresets)) {
+        _activePresets = val;
+      }
+      return entityEditor;
+    };
+    return utilRebind(entityEditor, dispatch14, "on");
   }
 
-  // modules/ui/tools/undo_redo.js
-  function uiToolUndoRedo(context) {
-    var tool = {
-      id: "undo_redo",
-      label: _t.append("toolbar.undo_redo")
-    };
-    var commands = [{
-      id: "undo",
-      cmd: uiCmd("\u2318Z"),
-      action: function() {
-        context.undo();
-      },
-      annotation: function() {
-        return context.history().undoAnnotation();
-      },
-      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")
-    }, {
-      id: "redo",
-      cmd: uiCmd("\u2318\u21E7Z"),
-      action: function() {
-        context.redo();
-      },
-      annotation: function() {
-        return context.history().redoAnnotation();
-      },
-      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "undo" : "redo")
-    }];
-    function editable() {
-      return context.mode() && context.mode().id !== "save" && context.map().editableDataEnabled(true);
-    }
-    tool.render = function(selection2) {
-      var tooltipBehavior = uiTooltip().placement("bottom").title(function(d) {
-        return d.annotation() ? _t.append(d.id + ".tooltip", { action: d.annotation() }) : _t.append(d.id + ".nothing");
-      }).keys(function(d) {
-        return [d.cmd];
-      }).scrollContainer(context.container().select(".top-toolbar"));
-      var lastPointerUpType;
-      var buttons = selection2.selectAll("button").data(commands).enter().append("button").attr("class", function(d) {
-        return "disabled " + d.id + "-button bar-button";
-      }).on("pointerup", function(d3_event) {
-        lastPointerUpType = d3_event.pointerType;
-      }).on("click", function(d3_event, d) {
-        d3_event.preventDefault();
-        var annotation = d.annotation();
-        if (editable() && annotation) {
-          d.action();
+  // modules/ui/preset_list.js
+  function uiPresetList(context) {
+    var dispatch14 = dispatch_default("cancel", "choose");
+    var _entityIDs;
+    var _currLoc;
+    var _currentPresets;
+    var _autofocus = false;
+    function presetList(selection2) {
+      if (!_entityIDs) return;
+      var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
+      selection2.html("");
+      var messagewrap = selection2.append("div").attr("class", "header fillL");
+      var message = messagewrap.append("h2").call(_t.append("inspector.choose"));
+      var direction = _mainLocalizer.textDirection() === "rtl" ? "backward" : "forward";
+      messagewrap.append("button").attr("class", "preset-choose").attr("title", _entityIDs.length === 1 ? _t("inspector.edit") : _t("inspector.edit_features")).on("click", function() {
+        dispatch14.call("cancel", this);
+      }).call(svgIcon("#iD-icon-".concat(direction)));
+      function initialKeydown(d3_event) {
+        if (search.property("value").length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes["\u232B"] || d3_event.keyCode === utilKeybinding.keyCodes["\u2326"])) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          operationDelete(context, _entityIDs)();
+        } else if (search.property("value").length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          context.undo();
+        } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
+          select_default2(this).on("keydown", keydown);
+          keydown.call(this, d3_event);
         }
-        if (editable() && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
-          var label = annotation ? _t.append(d.id + ".tooltip", { action: annotation }) : _t.append(d.id + ".nothing");
-          context.ui().flash.duration(2e3).iconName("#" + d.icon).iconClass(annotation ? "" : "disabled").label(label)();
+      }
+      function keydown(d3_event) {
+        if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"] && // if insertion point is at the end of the string
+        search.node().selectionStart === search.property("value").length) {
+          d3_event.preventDefault();
+          d3_event.stopPropagation();
+          var buttons = list2.selectAll(".preset-list-button");
+          if (!buttons.empty()) buttons.nodes()[0].focus();
         }
-        lastPointerUpType = null;
-      }).call(tooltipBehavior);
-      buttons.each(function(d) {
-        select_default2(this).call(svgIcon("#" + d.icon));
+      }
+      function keypress(d3_event) {
+        var value = search.property("value");
+        if (d3_event.keyCode === 13 && // ↩ Return
+        value.length) {
+          list2.selectAll(".preset-list-item:first-child").each(function(d2) {
+            d2.choose.call(this);
+          });
+        }
+      }
+      function inputevent() {
+        var value = search.property("value");
+        list2.classed("filtered", value.length);
+        var results, messageText;
+        if (value.length) {
+          results = presets.search(value, entityGeometries()[0], _currLoc);
+          messageText = _t.html("inspector.results", {
+            n: results.collection.length,
+            search: value
+          });
+        } else {
+          var entityPresets2 = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
+          results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets2);
+          messageText = _t.html("inspector.choose");
+        }
+        list2.call(drawList, results);
+        message.html(messageText);
+      }
+      var searchWrap = selection2.append("div").attr("class", "search-header");
+      searchWrap.call(svgIcon("#iD-icon-search", "pre-text"));
+      var search = searchWrap.append("input").attr("class", "preset-search-input").attr("placeholder", _t("inspector.search")).attr("type", "search").call(utilNoAuto).on("keydown", initialKeydown).on("keypress", keypress).on("input", debounce_default(inputevent));
+      if (_autofocus) {
+        search.node().focus();
+        setTimeout(function() {
+          search.node().focus();
+        }, 0);
+      }
+      var listWrap = selection2.append("div").attr("class", "inspector-body");
+      var entityPresets = _entityIDs.map((entityID) => _mainPresetIndex.match(context.graph().entity(entityID), context.graph()));
+      var list2 = listWrap.append("div").attr("class", "preset-list").call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc, entityPresets));
+      context.features().on("change.preset-list", updateForFeatureHiddenState);
+    }
+    function drawList(list2, presets) {
+      presets = presets.matchAllGeometry(entityGeometries());
+      var collection = presets.collection.reduce(function(collection2, preset) {
+        if (!preset) return collection2;
+        if (preset.members) {
+          if (preset.members.collection.filter(function(preset2) {
+            return preset2.addable();
+          }).length > 1) {
+            collection2.push(CategoryItem(preset));
+          }
+        } else if (preset.addable()) {
+          collection2.push(PresetItem(preset));
+        }
+        return collection2;
+      }, []);
+      var items = list2.selectAll(".preset-list-item").data(collection, function(d2) {
+        return d2.preset.id;
       });
-      context.keybinding().on(commands[0].cmd, function(d3_event) {
+      items.order();
+      items.exit().remove();
+      items.enter().append("div").attr("class", function(item) {
+        return "preset-list-item preset-" + item.preset.id.replace("/", "-");
+      }).classed("current", function(item) {
+        return _currentPresets.indexOf(item.preset) !== -1;
+      }).each(function(item) {
+        select_default2(this).call(item);
+      }).style("opacity", 0).transition().style("opacity", 1);
+      updateForFeatureHiddenState();
+    }
+    function itemKeydown(d3_event) {
+      var item = select_default2(this.closest(".preset-list-item"));
+      var parentItem = select_default2(item.node().parentNode.closest(".preset-list-item"));
+      if (d3_event.keyCode === utilKeybinding.keyCodes["\u2193"]) {
         d3_event.preventDefault();
-        if (editable())
-          commands[0].action();
-      }).on(commands[1].cmd, function(d3_event) {
+        d3_event.stopPropagation();
+        var nextItem = select_default2(item.node().nextElementSibling);
+        if (nextItem.empty()) {
+          if (!parentItem.empty()) {
+            nextItem = select_default2(parentItem.node().nextElementSibling);
+          }
+        } else if (select_default2(this).classed("expanded")) {
+          nextItem = item.select(".subgrid .preset-list-item:first-child");
+        }
+        if (!nextItem.empty()) {
+          nextItem.select(".preset-list-button").node().focus();
+        }
+      } else if (d3_event.keyCode === utilKeybinding.keyCodes["\u2191"]) {
         d3_event.preventDefault();
-        if (editable())
-          commands[1].action();
-      });
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.map().on("move.undo_redo", debouncedUpdate).on("drawn.undo_redo", debouncedUpdate);
-      context.history().on("change.undo_redo", function(difference) {
-        if (difference)
-          update();
-      });
-      context.on("enter.undo_redo", update);
-      function update() {
-        buttons.classed("disabled", function(d) {
-          return !editable() || !d.annotation();
-        }).each(function() {
-          var selection3 = select_default2(this);
-          if (!selection3.select(".tooltip.in").empty()) {
-            selection3.call(tooltipBehavior.updateContent);
+        d3_event.stopPropagation();
+        var previousItem = select_default2(item.node().previousElementSibling);
+        if (previousItem.empty()) {
+          if (!parentItem.empty()) {
+            previousItem = parentItem;
           }
-        });
+        } else if (previousItem.select(".preset-list-button").classed("expanded")) {
+          previousItem = previousItem.select(".subgrid .preset-list-item:last-child");
+        }
+        if (!previousItem.empty()) {
+          previousItem.select(".preset-list-button").node().focus();
+        } else {
+          var search = select_default2(this.closest(".preset-list-pane")).select(".preset-search-input");
+          search.node().focus();
+        }
+      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        if (!parentItem.empty()) {
+          parentItem.select(".preset-list-button").node().focus();
+        }
+      } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        item.datum().choose.call(select_default2(this).node());
       }
-    };
-    tool.uninstall = function() {
-      context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
-      context.map().on("move.undo_redo", null).on("drawn.undo_redo", null);
-      context.history().on("change.undo_redo", null);
-      context.on("enter.undo_redo", null);
-    };
-    return tool;
-  }
-
-  // modules/ui/top_toolbar.js
-  function uiTopToolbar(context) {
-    var sidebarToggle = uiToolSidebarToggle(context), modes = uiToolDrawModes(context), notes = uiToolNotes(context), undoRedo = uiToolUndoRedo(context), save = uiToolSave(context);
-    function notesEnabled() {
-      var noteLayer = context.layers().layer("notes");
-      return noteLayer && noteLayer.enabled();
     }
-    function topToolbar(bar) {
-      bar.on("wheel.topToolbar", function(d3_event) {
-        if (!d3_event.deltaX) {
-          bar.node().scrollLeft += d3_event.deltaY;
-        }
-      });
-      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
-      context.layers().on("change.topToolbar", debouncedUpdate);
-      update();
-      function update() {
-        var tools = [
-          sidebarToggle,
-          "spacer",
-          modes
-        ];
-        tools.push("spacer");
-        if (notesEnabled()) {
-          tools = tools.concat([notes, "spacer"]);
+    function CategoryItem(preset) {
+      var box, sublist, shown = false;
+      function item(selection2) {
+        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap category");
+        function click() {
+          var isExpanded = select_default2(this).classed("expanded");
+          var iconName = isExpanded ? _mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward" : "#iD-icon-down";
+          select_default2(this).classed("expanded", !isExpanded).attr("title", !isExpanded ? _t("icons.collapse") : _t("icons.expand"));
+          select_default2(this).selectAll("div.label-inner svg.icon use").attr("href", iconName);
+          item.choose();
         }
-        tools = tools.concat([undoRedo, save]);
-        var toolbarItems = bar.selectAll(".toolbar-item").data(tools, function(d) {
-          return d.id || d;
-        });
-        toolbarItems.exit().each(function(d) {
-          if (d.uninstall) {
-            d.uninstall();
+        var geometries = entityGeometries();
+        var button = wrap2.append("button").attr("class", "preset-list-button").attr("title", _t("icons.expand")).classed("expanded", false).call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", click).on("keydown", function(d3_event) {
+          if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2190" : "\u2192"]) {
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            if (!select_default2(this).classed("expanded")) {
+              click.call(this, d3_event);
+            }
+          } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === "rtl" ? "\u2192" : "\u2190"]) {
+            d3_event.preventDefault();
+            d3_event.stopPropagation();
+            if (select_default2(this).classed("expanded")) {
+              click.call(this, d3_event);
+            }
+          } else {
+            itemKeydown.call(this, d3_event);
           }
-        }).remove();
-        var itemsEnter = toolbarItems.enter().append("div").attr("class", function(d) {
-          var classes = "toolbar-item " + (d.id || d).replace("_", "-");
-          if (d.klass)
-            classes += " " + d.klass;
-          return classes;
-        });
-        var actionableItems = itemsEnter.filter(function(d) {
-          return d !== "spacer";
-        });
-        actionableItems.append("div").attr("class", "item-content").each(function(d) {
-          select_default2(this).call(d.render, bar);
-        });
-        actionableItems.append("div").attr("class", "item-label").each(function(d) {
-          d.label(select_default2(this));
         });
+        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
+        label.append("div").attr("class", "namepart").call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-backward" : "#iD-icon-forward", "inline")).append("span").call(preset.nameLabel()).append("span").text("\u2026");
+        box = selection2.append("div").attr("class", "subgrid").style("max-height", "0px").style("opacity", 0);
+        box.append("div").attr("class", "arrow");
+        sublist = box.append("div").attr("class", "preset-list fillL3");
       }
-    }
-    return topToolbar;
-  }
-
-  // modules/ui/zoom_to_selection.js
-  function uiZoomToSelection(context) {
-    function isDisabled() {
-      var mode = context.mode();
-      return !mode || !mode.zoomToSelected;
-    }
-    var _lastPointerUpType;
-    function pointerup(d3_event) {
-      _lastPointerUpType = d3_event.pointerType;
-    }
-    function click(d3_event) {
-      d3_event.preventDefault();
-      if (isDisabled()) {
-        if (_lastPointerUpType === "touch" || _lastPointerUpType === "pen") {
-          context.ui().flash.duration(2e3).iconName("#iD-icon-framed-dot").iconClass("disabled").label(_t.append("inspector.zoom_to.no_selection"))();
-        }
-      } else {
-        var mode = context.mode();
-        if (mode && mode.zoomToSelected) {
-          mode.zoomToSelected();
+      item.choose = function() {
+        if (!box || !sublist) return;
+        if (shown) {
+          shown = false;
+          box.transition().duration(200).style("opacity", "0").style("max-height", "0px").style("padding-bottom", "0px");
+        } else {
+          shown = true;
+          var members = preset.members.matchAllGeometry(entityGeometries());
+          sublist.call(drawList, members);
+          box.transition().duration(200).style("opacity", "1").style("max-height", 200 + members.collection.length * 190 + "px").style("padding-bottom", "10px");
         }
+      };
+      item.preset = preset;
+      return item;
+    }
+    function PresetItem(preset) {
+      function item(selection2) {
+        var wrap2 = selection2.append("div").attr("class", "preset-list-button-wrap");
+        var geometries = entityGeometries();
+        var button = wrap2.append("button").attr("class", "preset-list-button").call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on("click", item.choose).on("keydown", itemKeydown);
+        var label = button.append("div").attr("class", "label").append("div").attr("class", "label-inner");
+        var nameparts = [
+          preset.nameLabel(),
+          preset.subtitleLabel()
+        ].filter(Boolean);
+        label.selectAll(".namepart").data(nameparts, (d2) => d2.stringId).enter().append("div").attr("class", "namepart").text("").each(function(d2) {
+          d2(select_default2(this));
+        });
+        wrap2.call(item.reference.button);
+        selection2.call(item.reference.body);
       }
-      _lastPointerUpType = null;
+      item.choose = function() {
+        if (select_default2(this).classed("disabled")) return;
+        if (!context.inIntro()) {
+          _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
+        }
+        context.perform(
+          function(graph) {
+            for (var i3 in _entityIDs) {
+              var entityID = _entityIDs[i3];
+              var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
+              graph = actionChangePreset(entityID, oldPreset, preset)(graph);
+            }
+            return graph;
+          },
+          _t("operations.change_tags.annotation")
+        );
+        context.validator().validate();
+        dispatch14.call("choose", this, preset);
+      };
+      item.help = function(d3_event) {
+        d3_event.stopPropagation();
+        item.reference.toggle();
+      };
+      item.preset = preset;
+      item.reference = uiTagReference(preset.reference(), context);
+      return item;
     }
-    return function(selection2) {
-      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function() {
-        if (isDisabled()) {
-          return _t.append("inspector.zoom_to.no_selection");
+    function updateForFeatureHiddenState() {
+      if (!_entityIDs.every(context.hasEntity)) return;
+      var geometries = entityGeometries();
+      var button = context.container().selectAll(".preset-list .preset-list-button");
+      button.call(uiTooltip().destroyAny);
+      button.each(function(item, index) {
+        var hiddenPresetFeaturesId;
+        for (var i3 in geometries) {
+          hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i3]);
+          if (hiddenPresetFeaturesId) break;
         }
-        return _t.append("inspector.zoom_to.title");
-      }).keys([_t("inspector.zoom_to.key")]);
-      var button = selection2.append("button").on("pointerup", pointerup).on("click", click).call(svgIcon("#iD-icon-framed-dot", "light")).call(tooltipBehavior);
-      function setEnabledState() {
-        button.classed("disabled", isDisabled());
-        if (!button.select(".tooltip.in").empty()) {
-          button.call(tooltipBehavior.updateContent);
+        var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
+        select_default2(this).classed("disabled", isHiddenPreset);
+        if (isHiddenPreset) {
+          var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
+          select_default2(this).call(
+            uiTooltip().title(() => _t.append("inspector.hidden_preset." + (isAutoHidden ? "zoom" : "manual"), {
+              features: _t("feature." + hiddenPresetFeaturesId + ".description")
+            })).placement(index < 2 ? "bottom" : "top")
+          );
         }
-      }
-      context.on("enter.uiZoomToSelection", setEnabledState);
-      setEnabledState();
-    };
-  }
-
-  // modules/ui/pane.js
-  function uiPane(id2, context) {
-    var _key;
-    var _label = "";
-    var _description = "";
-    var _iconName = "";
-    var _sections;
-    var _paneSelection = select_default2(null);
-    var _paneTooltip;
-    var pane = {
-      id: id2
-    };
-    pane.label = function(val) {
-      if (!arguments.length)
-        return _label;
-      _label = val;
-      return pane;
-    };
-    pane.key = function(val) {
-      if (!arguments.length)
-        return _key;
-      _key = val;
-      return pane;
-    };
-    pane.description = function(val) {
-      if (!arguments.length)
-        return _description;
-      _description = val;
-      return pane;
-    };
-    pane.iconName = function(val) {
-      if (!arguments.length)
-        return _iconName;
-      _iconName = val;
-      return pane;
-    };
-    pane.sections = function(val) {
-      if (!arguments.length)
-        return _sections;
-      _sections = val;
-      return pane;
-    };
-    pane.selection = function() {
-      return _paneSelection;
-    };
-    function hidePane() {
-      context.ui().togglePanes();
+      });
     }
-    pane.togglePane = function(d3_event) {
-      if (d3_event)
-        d3_event.preventDefault();
-      _paneTooltip.hide();
-      context.ui().togglePanes(!_paneSelection.classed("shown") ? _paneSelection : void 0);
+    presetList.autofocus = function(val) {
+      if (!arguments.length) return _autofocus;
+      _autofocus = val;
+      return presetList;
     };
-    pane.renderToggleButton = function(selection2) {
-      if (!_paneTooltip) {
-        _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _description).keys([_key]);
+    presetList.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _currLoc = null;
+      if (_entityIDs && _entityIDs.length) {
+        const extent = _entityIDs.reduce(function(extent2, entityID) {
+          var entity = context.graph().entity(entityID);
+          return extent2.extend(entity.extent(context.graph()));
+        }, geoExtent());
+        _currLoc = extent.center();
+        var presets = _entityIDs.map(function(entityID) {
+          return _mainPresetIndex.match(context.entity(entityID), context.graph());
+        });
+        presetList.presets(presets);
       }
-      selection2.append("button").on("click", pane.togglePane).call(svgIcon("#" + _iconName, "light")).call(_paneTooltip);
+      return presetList;
     };
-    pane.renderContent = function(selection2) {
-      if (_sections) {
-        _sections.forEach(function(section) {
-          selection2.call(section.render);
-        });
-      }
+    presetList.presets = function(val) {
+      if (!arguments.length) return _currentPresets;
+      _currentPresets = val;
+      return presetList;
     };
-    pane.renderPane = function(selection2) {
-      _paneSelection = selection2.append("div").attr("class", "fillL map-pane hide " + id2 + "-pane").attr("pane", id2);
-      var heading = _paneSelection.append("div").attr("class", "pane-heading");
-      heading.append("h2").text("").call(_label);
-      heading.append("button").attr("title", _t("icons.close")).on("click", hidePane).call(svgIcon("#iD-icon-close"));
-      _paneSelection.append("div").attr("class", "pane-content").call(pane.renderContent);
-      if (_key) {
-        context.keybinding().on(_key, pane.togglePane);
+    function entityGeometries() {
+      var counts = {};
+      for (var i3 in _entityIDs) {
+        var entityID = _entityIDs[i3];
+        var entity = context.entity(entityID);
+        var geometry = entity.geometry(context.graph());
+        if (geometry === "vertex" && entity.isOnAddressLine(context.graph())) {
+          geometry = "point";
+        }
+        if (!counts[geometry]) counts[geometry] = 0;
+        counts[geometry] += 1;
       }
-    };
-    return pane;
+      return Object.keys(counts).sort(function(geom1, geom2) {
+        return counts[geom2] - counts[geom1];
+      });
+    }
+    return utilRebind(presetList, dispatch14, "on");
   }
 
-  // modules/ui/sections/background_display_options.js
-  function uiSectionBackgroundDisplayOptions(context) {
-    var section = uiSection("background-display-options", context).label(() => _t.append("background.display_options")).disclosureContent(renderDisclosureContent);
-    var _storedOpacity = corePreferences("background-opacity");
-    var _minVal = 0;
-    var _maxVal = 3;
-    var _sliders = ["brightness", "contrast", "saturation", "sharpness"];
-    var _options = {
-      brightness: _storedOpacity !== null ? +_storedOpacity : 1,
-      contrast: 1,
-      saturation: 1,
-      sharpness: 1
-    };
-    function clamp3(x, min3, max3) {
-      return Math.max(min3, Math.min(x, max3));
-    }
-    function updateValue(d, val) {
-      val = clamp3(val, _minVal, _maxVal);
-      _options[d] = val;
-      context.background()[d](val);
-      if (d === "brightness") {
-        corePreferences("background-opacity", val);
+  // modules/ui/inspector.js
+  function uiInspector(context) {
+    var presetList = uiPresetList(context);
+    var entityEditor = uiEntityEditor(context);
+    var wrap2 = select_default2(null), presetPane = select_default2(null), editorPane = select_default2(null);
+    var _state = "select";
+    var _entityIDs;
+    var _newFeature = false;
+    function inspector(selection2) {
+      presetList.entityIDs(_entityIDs).autofocus(_newFeature).on("choose", inspector.setPreset).on("cancel", function() {
+        inspector.setPreset();
+      });
+      entityEditor.state(_state).entityIDs(_entityIDs).on("choose", inspector.showList);
+      wrap2 = selection2.selectAll(".panewrap").data([0]);
+      var enter = wrap2.enter().append("div").attr("class", "panewrap");
+      enter.append("div").attr("class", "preset-list-pane pane");
+      enter.append("div").attr("class", "entity-editor-pane pane");
+      wrap2 = wrap2.merge(enter);
+      presetPane = wrap2.selectAll(".preset-list-pane");
+      editorPane = wrap2.selectAll(".entity-editor-pane");
+      function shouldDefaultToPresetList() {
+        if (_state !== "select") return false;
+        if (_entityIDs.length !== 1) return false;
+        var entityID = _entityIDs[0];
+        var entity = context.hasEntity(entityID);
+        if (!entity) return false;
+        if (entity.hasNonGeometryTags()) return false;
+        if (_newFeature) return true;
+        if (entity.geometry(context.graph()) !== "vertex") return false;
+        if (context.graph().parentRelations(entity).length) return false;
+        if (context.validator().getEntityIssues(entityID).length) return false;
+        if (entity.isHighwayIntersection(context.graph())) return false;
+        return true;
       }
-      section.reRender();
+      if (shouldDefaultToPresetList()) {
+        wrap2.style("right", "-100%");
+        editorPane.classed("hide", true);
+        presetPane.classed("hide", false).call(presetList);
+      } else {
+        wrap2.style("right", "0%");
+        presetPane.classed("hide", true);
+        editorPane.classed("hide", false).call(entityEditor);
+      }
+      var footer = selection2.selectAll(".footer").data([0]);
+      footer = footer.enter().append("div").attr("class", "footer").merge(footer);
+      footer.call(
+        uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0]))
+      );
     }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".display-options-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "display-options-container controls-list");
-      var slidersEnter = containerEnter.selectAll(".display-control").data(_sliders).enter().append("label").attr("class", function(d) {
-        return "display-control display-control-" + d;
-      });
-      slidersEnter.html(function(d) {
-        return _t.html("background." + d);
-      }).append("span").attr("class", function(d) {
-        return "display-option-value display-option-value-" + d;
-      });
-      var sildersControlEnter = slidersEnter.append("div").attr("class", "control-wrap");
-      sildersControlEnter.append("input").attr("class", function(d) {
-        return "display-option-input display-option-input-" + d;
-      }).attr("type", "range").attr("min", _minVal).attr("max", _maxVal).attr("step", "0.05").on("input", function(d3_event, d) {
-        var val = select_default2(this).property("value");
-        if (!val && d3_event && d3_event.target) {
-          val = d3_event.target.value;
-        }
-        updateValue(d, val);
+    inspector.showList = function(presets) {
+      presetPane.classed("hide", false);
+      wrap2.transition().styleTween("right", function() {
+        return value_default("0%", "-100%");
+      }).on("end", function() {
+        editorPane.classed("hide", true);
       });
-      sildersControlEnter.append("button").attr("title", function(d) {
-        return `${_t("background.reset")} ${_t("background." + d)}`;
-      }).attr("class", function(d) {
-        return "display-option-reset display-option-reset-" + d;
-      }).on("click", function(d3_event, d) {
-        if (d3_event.button !== 0)
-          return;
-        updateValue(d, 1);
-      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
-      containerEnter.append("a").attr("class", "display-option-resetlink").attr("role", "button").attr("href", "#").call(_t.append("background.reset_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        for (var i2 = 0; i2 < _sliders.length; i2++) {
-          updateValue(_sliders[i2], 1);
+      if (presets) {
+        presetList.presets(presets);
+      }
+      presetPane.call(presetList.autofocus(true));
+    };
+    inspector.setPreset = function(preset) {
+      if (preset && preset.id === "type/multipolygon") {
+        presetPane.call(presetList.autofocus(true));
+      } else {
+        editorPane.classed("hide", false);
+        wrap2.transition().styleTween("right", function() {
+          return value_default("-100%", "0%");
+        }).on("end", function() {
+          presetPane.classed("hide", true);
+        });
+        if (preset) {
+          entityEditor.presets([preset]);
         }
-      });
-      container = containerEnter.merge(container);
-      container.selectAll(".display-option-input").property("value", function(d) {
-        return _options[d];
-      });
-      container.selectAll(".display-option-value").text(function(d) {
-        return Math.floor(_options[d] * 100) + "%";
-      });
-      container.selectAll(".display-option-reset").classed("disabled", function(d) {
-        return _options[d] === 1;
-      });
-      if (containerEnter.size() && _options.brightness !== 1) {
-        context.background().brightness(_options.brightness);
+        editorPane.call(entityEditor);
       }
-    }
-    return section;
+    };
+    inspector.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      entityEditor.state(_state);
+      context.container().selectAll(".field-help-body").remove();
+      return inspector;
+    };
+    inspector.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return inspector;
+    };
+    inspector.newFeature = function(val) {
+      if (!arguments.length) return _newFeature;
+      _newFeature = val;
+      return inspector;
+    };
+    return inspector;
   }
 
-  // modules/ui/settings/custom_background.js
-  function uiSettingsCustomBackground() {
-    var dispatch10 = dispatch_default("change");
-    function render(selection2) {
-      var _origSettings = {
-        template: corePreferences("background-custom-template")
-      };
-      var _currSettings = {
-        template: corePreferences("background-custom-template")
-      };
-      var example = "https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png";
-      var modal = uiConfirm(selection2).okButton();
-      modal.classed("settings-modal settings-custom-background", true);
-      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_background.header"));
-      var textSection = modal.select(".modal-section.message-text");
-      var instructions = `${_t.html("settings.custom_background.instructions.info")}
-
-#### ${_t.html("settings.custom_background.instructions.wms.tokens_label")}
-* ${_t.html("settings.custom_background.instructions.wms.tokens.proj")}
-* ${_t.html("settings.custom_background.instructions.wms.tokens.wkid")}
-* ${_t.html("settings.custom_background.instructions.wms.tokens.dimensions")}
-* ${_t.html("settings.custom_background.instructions.wms.tokens.bbox")}
-
-#### ${_t.html("settings.custom_background.instructions.tms.tokens_label")}
-* ${_t.html("settings.custom_background.instructions.tms.tokens.xyz")}
-* ${_t.html("settings.custom_background.instructions.tms.tokens.flipped_y")}
-* ${_t.html("settings.custom_background.instructions.tms.tokens.switch")}
-* ${_t.html("settings.custom_background.instructions.tms.tokens.quadtile")}
-* ${_t.html("settings.custom_background.instructions.tms.tokens.scale_factor")}
-
-#### ${_t.html("settings.custom_background.instructions.example")}
-\`${example}\``;
-      textSection.append("div").attr("class", "instructions-template").html(marked(instructions));
-      textSection.append("textarea").attr("class", "field-template").attr("placeholder", _t("settings.custom_background.template.placeholder")).call(utilNoAuto).property("value", _currSettings.template);
-      var buttonSection = modal.select(".modal-section.buttons");
-      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
-      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
-      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
-      function isSaveDisabled() {
-        return null;
-      }
-      function clickCancel() {
-        textSection.select(".field-template").property("value", _origSettings.template);
-        corePreferences("background-custom-template", _origSettings.template);
-        this.blur();
-        modal.close();
-      }
-      function clickSave() {
-        _currSettings.template = textSection.select(".field-template").property("value");
-        corePreferences("background-custom-template", _currSettings.template);
-        this.blur();
-        modal.close();
-        dispatch10.call("change", this, _currSettings);
+  // modules/ui/keepRight_details.js
+  function uiKeepRightDetails(context) {
+    let _qaItem;
+    function issueDetail(d2) {
+      const { itemType, parentIssueType } = d2;
+      const unknown = { html: _t.html("inspector.unknown") };
+      let replacements = d2.replacements || {};
+      replacements.default = unknown;
+      if (_mainLocalizer.hasTextForStringId("QA.keepRight.errorTypes.".concat(itemType, ".title"))) {
+        return _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
+      } else {
+        return _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
       }
     }
-    return utilRebind(render, dispatch10, "on");
-  }
-
-  // modules/ui/sections/background_list.js
-  function uiSectionBackgroundList(context) {
-    var _backgroundList = select_default2(null);
-    var _customSource = context.background().findSource("custom");
-    var _settingsCustomBackground = uiSettingsCustomBackground(context).on("change", customChanged);
-    var section = uiSection("background-list", context).label(() => _t.append("background.backgrounds")).disclosureContent(renderDisclosureContent);
-    function previousBackgroundID() {
-      return corePreferences("background-last-used-toggle");
-    }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-background-list").data([0]);
-      _backgroundList = container.enter().append("ul").attr("class", "layer-list layer-background-list").attr("dir", "auto").merge(container);
-      var bgExtrasListEnter = selection2.selectAll(".bg-extras-list").data([0]).enter().append("ul").attr("class", "layer-list bg-extras-list");
-      var minimapLabelEnter = bgExtrasListEnter.append("li").attr("class", "minimap-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("background.minimap.tooltip")).keys([_t("background.minimap.key")]).placement("top")
-      );
-      minimapLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        uiMapInMap.toggle();
-      });
-      minimapLabelEnter.append("span").call(_t.append("background.minimap.description"));
-      var panelLabelEnter = bgExtrasListEnter.append("li").attr("class", "background-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("background.panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.background.key"))]).placement("top")
-      );
-      panelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("background");
-      });
-      panelLabelEnter.append("span").call(_t.append("background.panel.description"));
-      var locPanelLabelEnter = bgExtrasListEnter.append("li").attr("class", "location-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("background.location_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.location.key"))]).placement("top")
+    function keepRightDetails(selection2) {
+      const details = selection2.selectAll(".error-details").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
       );
-      locPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("location");
-      });
-      locPanelLabelEnter.append("span").call(_t.append("background.location_panel.description"));
-      selection2.selectAll(".imagery-faq").data([0]).enter().append("div").attr("class", "imagery-faq").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/develop/FAQ.md#how-can-i-report-an-issue-with-background-imagery").append("span").call(_t.append("background.imagery_problem_faq"));
-      _backgroundList.call(drawListItems, "radio", function(d3_event, d) {
-        chooseBackground(d);
-      }, function(d) {
-        return !d.isHidden() && !d.overlay;
-      });
-    }
-    function setTooltips(selection2) {
-      selection2.each(function(d, i2, nodes) {
-        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 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) {
-          item.call(
-            uiTooltip().placement(placement).title(() => description || d.label())
-          );
+      details.exit().remove();
+      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
+      const descriptionEnter = detailsEnter.append("div").attr("class", "qa-details-subsection");
+      descriptionEnter.append("h4").call(_t.append("QA.keepRight.detail_description"));
+      descriptionEnter.append("div").attr("class", "qa-details-description-text").html(issueDetail);
+      let relatedEntities = [];
+      descriptionEnter.selectAll(".error_entity_link, .error_object_link").attr("href", "#").each(function() {
+        const link3 = select_default2(this);
+        const isObjectLink = link3.classed("error_object_link");
+        const entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
+        const entity = context.hasEntity(entityID);
+        relatedEntities.push(entityID);
+        link3.on("mouseenter", () => {
+          utilHighlightEntities([entityID], true, context);
+        }).on("mouseleave", () => {
+          utilHighlightEntities([entityID], false, context);
+        }).on("click", (d3_event) => {
+          d3_event.preventDefault();
+          utilHighlightEntities([entityID], false, context);
+          const osmlayer = context.layers().layer("osm");
+          if (!osmlayer.enabled()) {
+            osmlayer.enabled(true);
+          }
+          context.map().centerZoomEase(_qaItem.loc, 20);
+          if (entity) {
+            context.enter(modeSelect(context, [entityID]));
+          } else {
+            context.loadEntity(entityID, (err, result) => {
+              if (err) return;
+              const entity2 = result.data.find((e3) => e3.id === entityID);
+              if (entity2) context.enter(modeSelect(context, [entityID]));
+            });
+          }
+        });
+        if (entity) {
+          let name = utilDisplayName(entity);
+          if (!name && !isObjectLink) {
+            const preset = _mainPresetIndex.match(entity, context.graph());
+            name = preset && !preset.isFallback() && preset.name();
+          }
+          if (name) {
+            this.innerText = name;
+          }
         }
       });
+      context.features().forceVisible(relatedEntities);
+      context.map().pan([0, 0]);
     }
-    function drawListItems(layerList, type3, 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;
-      });
-      var layerLinks = layerList.selectAll("li").data(sources, function(d, i2) {
-        return d.id + "---" + i2;
-      });
-      layerLinks.exit().remove();
-      var enter = layerLinks.enter().append("li").classed("layer-custom", function(d) {
-        return d.id === "custom";
-      }).classed("best", function(d) {
-        return d.best();
-      });
-      var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", "background-layer").attr("value", function(d) {
-        return d.id;
-      }).on("change", change);
-      label.append("span").each(function(d) {
-        d.label()(select_default2(this));
-      });
-      enter.filter(function(d) {
-        return d.id === "custom";
-      }).append("button").attr("class", "layer-browse").call(
-        uiTooltip().title(() => _t.append("settings.custom_background.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        editCustom();
-      }).call(svgIcon("#iD-icon-more"));
-      enter.filter(function(d) {
-        return d.best();
-      }).append("div").attr("class", "best").call(
-        uiTooltip().title(() => _t.append("background.best_imagery")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).append("span").text("\u2605");
-      layerList.call(updateLayerSelections);
-    }
-    function updateLayerSelections(selection2) {
-      function active(d) {
-        return context.background().showsLayer(d);
-      }
-      selection2.selectAll("li").classed("active", active).classed("switch", function(d) {
-        return d.id === previousBackgroundID();
-      }).call(setTooltips).selectAll("input").property("checked", active);
-    }
-    function chooseBackground(d) {
-      if (d.id === "custom" && !d.template()) {
-        return editCustom();
-      }
-      var previousBackground = context.background().baseLayerSource();
-      corePreferences("background-last-used-toggle", previousBackground.id);
-      corePreferences("background-last-used", d.id);
-      context.background().baseLayerSource(d);
-    }
-    function customChanged(d) {
-      if (d && d.template) {
-        _customSource.template(d.template);
-        chooseBackground(_customSource);
+    keepRightDetails.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return keepRightDetails;
+    };
+    return keepRightDetails;
+  }
+
+  // modules/ui/keepRight_header.js
+  function uiKeepRightHeader() {
+    let _qaItem;
+    function issueTitle(d2) {
+      const { itemType, parentIssueType } = d2;
+      const unknown = _t.html("inspector.unknown");
+      let replacements = d2.replacements || {};
+      replacements.default = { html: unknown };
+      if (_mainLocalizer.hasTextForStringId("QA.keepRight.errorTypes.".concat(itemType, ".title"))) {
+        return _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
       } else {
-        _customSource.template("");
-        chooseBackground(context.background().findSource("none"));
+        return _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
       }
     }
-    function editCustom() {
-      context.container().call(_settingsCustomBackground);
+    function keepRightHeader(selection2) {
+      const header = selection2.selectAll(".qa-header").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      header.exit().remove();
+      const headerEnter = header.enter().append("div").attr("class", "qa-header");
+      const iconEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d2) => d2.id < 0);
+      iconEnter.append("div").attr("class", (d2) => "preset-icon-28 qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.parentIssueType)).call(svgIcon("#iD-icon-bolt", "qaItem-fill"));
+      headerEnter.append("div").attr("class", "qa-header-label").html(issueTitle);
     }
-    context.background().on("change.background_list", function() {
-      _backgroundList.call(updateLayerSelections);
-    });
-    context.map().on(
-      "move.background_list",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
+    keepRightHeader.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return keepRightHeader;
+    };
+    return keepRightHeader;
   }
 
-  // modules/ui/sections/background_offset.js
-  function uiSectionBackgroundOffset(context) {
-    var section = uiSection("background-offset", context).label(() => _t.append("background.fix_misalignment")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
-    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
-    var _directions = [
-      ["top", [0, -0.5]],
-      ["left", [-0.5, 0]],
-      ["right", [0.5, 0]],
-      ["bottom", [0, 0.5]]
-    ];
-    function updateValue() {
-      var meters = geoOffsetToMeters(context.background().offset());
-      var x = +meters[0].toFixed(2);
-      var y = +meters[1].toFixed(2);
-      context.container().selectAll(".nudge-inner-rect").select("input").classed("error", false).property("value", x + ", " + y);
-      context.container().selectAll(".nudge-reset").classed("disabled", function() {
-        return x === 0 && y === 0;
-      });
-    }
-    function resetOffset() {
-      context.background().offset([0, 0]);
-      updateValue();
-    }
-    function nudge(d) {
-      context.background().nudge(d, context.map().zoom());
-      updateValue();
-    }
-    function inputOffset() {
-      var input = select_default2(this);
-      var d = input.node().value;
-      if (d === "")
-        return resetOffset();
-      d = d.replace(/;/g, ",").split(",").map(function(n2) {
-        return !isNaN(n2) && n2;
-      });
-      if (d.length !== 2 || !d[0] || !d[1]) {
-        input.classed("error", true);
-        return;
-      }
-      context.background().offset(geoMetersToOffset(d));
-      updateValue();
-    }
-    function dragOffset(d3_event) {
-      if (d3_event.button !== 0)
-        return;
-      var origin = [d3_event.clientX, d3_event.clientY];
-      var pointerId = d3_event.pointerId || "mouse";
-      context.container().append("div").attr("class", "nudge-surface");
-      select_default2(window).on(_pointerPrefix + "move.drag-bg-offset", pointermove).on(_pointerPrefix + "up.drag-bg-offset", pointerup);
-      if (_pointerPrefix === "pointer") {
-        select_default2(window).on("pointercancel.drag-bg-offset", pointerup);
-      }
-      function pointermove(d3_event2) {
-        if (pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
-        var latest = [d3_event2.clientX, d3_event2.clientY];
-        var d = [
-          -(origin[0] - latest[0]) / 4,
-          -(origin[1] - latest[1]) / 4
-        ];
-        origin = latest;
-        nudge(d);
-      }
-      function pointerup(d3_event2) {
-        if (pointerId !== (d3_event2.pointerId || "mouse"))
-          return;
-        if (d3_event2.button !== 0)
-          return;
-        context.container().selectAll(".nudge-surface").remove();
-        select_default2(window).on(".drag-bg-offset", null);
+  // modules/ui/view_on_keepRight.js
+  function uiViewOnKeepRight() {
+    let _qaItem;
+    function viewOnKeepRight(selection2) {
+      let url;
+      if (services.keepRight && _qaItem instanceof QAItem) {
+        url = services.keepRight.issueURL(_qaItem);
       }
+      const link3 = selection2.selectAll(".view-on-keepRight").data(url ? [url] : []);
+      link3.exit().remove();
+      const linkEnter = link3.enter().append("a").attr("class", "view-on-keepRight").attr("target", "_blank").attr("rel", "noopener").attr("href", (d2) => d2).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("inspector.view_on_keepRight"));
     }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".nudge-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "nudge-container");
-      containerEnter.append("div").attr("class", "nudge-instructions").call(_t.append("background.offset"));
-      var nudgeWrapEnter = containerEnter.append("div").attr("class", "nudge-controls-wrap");
-      var nudgeEnter = nudgeWrapEnter.append("div").attr("class", "nudge-outer-rect").on(_pointerPrefix + "down", dragOffset);
-      nudgeEnter.append("div").attr("class", "nudge-inner-rect").append("input").attr("type", "text").attr("aria-label", _t("background.offset_label")).on("change", inputOffset);
-      nudgeWrapEnter.append("div").selectAll("button").data(_directions).enter().append("button").attr("title", function(d) {
-        return _t(`background.nudge.${d[0]}`);
-      }).attr("class", function(d) {
-        return d[0] + " nudge";
-      }).on("click", function(d3_event, d) {
-        nudge(d[1]);
-      });
-      nudgeWrapEnter.append("button").attr("title", _t("background.reset")).attr("class", "nudge-reset disabled").on("click", function(d3_event) {
-        d3_event.preventDefault();
-        resetOffset();
-      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
-      updateValue();
-    }
-    context.background().on("change.backgroundOffset-update", updateValue);
-    return section;
+    viewOnKeepRight.what = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return viewOnKeepRight;
+    };
+    return viewOnKeepRight;
   }
 
-  // modules/ui/sections/overlay_list.js
-  function uiSectionOverlayList(context) {
-    var section = uiSection("overlay-list", context).label(() => _t.append("background.overlays")).disclosureContent(renderDisclosureContent);
-    var _overlayList = select_default2(null);
-    function setTooltips(selection2) {
-      selection2.each(function(d, i2, nodes) {
-        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 isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
-        item.call(uiTooltip().destroyAny);
-        if (description || isOverflowing) {
-          item.call(
-            uiTooltip().placement(placement).title(() => description || d.name())
-          );
-        }
-      });
+  // modules/ui/keepRight_editor.js
+  function uiKeepRightEditor(context) {
+    const dispatch14 = dispatch_default("change");
+    const qaDetails = uiKeepRightDetails(context);
+    const qaHeader = uiKeepRightHeader(context);
+    let _qaItem;
+    function keepRightEditor(selection2) {
+      const headerEnter = selection2.selectAll(".header").data([0]).enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("QA.keepRight.title"));
+      let body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      const editor = body.selectAll(".qa-editor").data([0]);
+      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
+      const footer = selection2.selectAll(".footer").data([0]);
+      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnKeepRight(context).what(_qaItem));
     }
-    function updateLayerSelections(selection2) {
-      function active(d) {
-        return context.background().showsLayer(d);
+    function keepRightSaveSection(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      const isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
+      let saveSection = selection2.selectAll(".qa-save").data(
+        isShown ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      saveSection.exit().remove();
+      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
+      saveSectionEnter.append("h4").attr("class", ".qa-save-header").call(_t.append("QA.keepRight.comment"));
+      saveSectionEnter.append("textarea").attr("class", "new-comment-input").attr("placeholder", _t("QA.keepRight.comment_placeholder")).attr("maxlength", 1e3).property("value", (d2) => d2.newComment || d2.comment).call(utilNoAuto).on("input", changeInput).on("blur", changeInput);
+      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
+      function changeInput() {
+        const input = select_default2(this);
+        let val = input.property("value").trim();
+        if (val === _qaItem.comment) {
+          val = void 0;
+        }
+        _qaItem = _qaItem.update({ newComment: val });
+        const qaService = services.keepRight;
+        if (qaService) {
+          qaService.replaceItem(_qaItem);
+        }
+        saveSection.call(qaSaveButtons);
       }
-      selection2.selectAll("li").classed("active", active).call(setTooltips).selectAll("input").property("checked", active);
-    }
-    function chooseOverlay(d3_event, d) {
-      d3_event.preventDefault();
-      context.background().toggleOverlayLayer(d);
-      _overlayList.call(updateLayerSelections);
-      document.activeElement.blur();
     }
-    function drawListItems(layerList, type3, 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();
+    function qaSaveButtons(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d2) => d2.status + d2.id);
+      buttonSection.exit().remove();
+      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
+      buttonEnter.append("button").attr("class", "button comment-button action").call(_t.append("QA.keepRight.save_comment"));
+      buttonEnter.append("button").attr("class", "button close-button action");
+      buttonEnter.append("button").attr("class", "button ignore-button action");
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.select(".comment-button").attr("disabled", (d2) => d2.newComment ? null : true).on("click.comment", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.keepRight;
+        if (qaService) {
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
+        }
       });
-      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("span").each(function(d) {
-        d.label()(select_default2(this));
+      buttonSection.select(".close-button").html((d2) => {
+        const andComment = d2.newComment ? "_comment" : "";
+        return _t.html("QA.keepRight.close".concat(andComment));
+      }).on("click.close", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.keepRight;
+        if (qaService) {
+          d2.newStatus = "ignore_t";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
+        }
       });
-      layerList.selectAll("li").sort(sortSources);
-      layerList.call(updateLayerSelections);
-      function sortSources(a, b) {
-        return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
-      }
-    }
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-overlay-list").data([0]);
-      _overlayList = container.enter().append("ul").attr("class", "layer-list layer-overlay-list").attr("dir", "auto").merge(container);
-      _overlayList.call(drawListItems, "checkbox", chooseOverlay, function(d) {
-        return !d.isHidden() && d.overlay;
+      buttonSection.select(".ignore-button").html((d2) => {
+        const andComment = d2.newComment ? "_comment" : "";
+        return _t.html("QA.keepRight.ignore".concat(andComment));
+      }).on("click.ignore", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.keepRight;
+        if (qaService) {
+          d2.newStatus = "ignore";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
+        }
       });
     }
-    context.map().on(
-      "move.overlay_list",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
-  }
-
-  // modules/ui/panes/background.js
-  function uiPaneBackground(context) {
-    var backgroundPane = uiPane("background", context).key(_t("background.key")).label(_t.append("background.title")).description(_t.append("background.description")).iconName("iD-icon-layers").sections([
-      uiSectionBackgroundList(context),
-      uiSectionOverlayList(context),
-      uiSectionBackgroundDisplayOptions(context),
-      uiSectionBackgroundOffset(context)
-    ]);
-    return backgroundPane;
+    keepRightEditor.error = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return keepRightEditor;
+    };
+    return utilRebind(keepRightEditor, dispatch14, "on");
   }
 
-  // modules/ui/panes/help.js
-  function uiPaneHelp(context) {
-    var docKeys = [
-      ["help", [
-        "welcome",
-        "open_data_h",
-        "open_data",
-        "before_start_h",
-        "before_start",
-        "open_source_h",
-        "open_source",
-        "open_source_help"
-      ]],
-      ["overview", [
-        "navigation_h",
-        "navigation_drag",
-        "navigation_zoom",
-        "features_h",
-        "features",
-        "nodes_ways"
-      ]],
-      ["editing", [
-        "select_h",
-        "select_left_click",
-        "select_right_click",
-        "select_space",
-        "multiselect_h",
-        "multiselect",
-        "multiselect_shift_click",
-        "multiselect_lasso",
-        "undo_redo_h",
-        "undo_redo",
-        "save_h",
-        "save",
-        "save_validation",
-        "upload_h",
-        "upload",
-        "backups_h",
-        "backups",
-        "keyboard_h",
-        "keyboard"
-      ]],
-      ["feature_editor", [
-        "intro",
-        "definitions",
-        "type_h",
-        "type",
-        "type_picker",
-        "fields_h",
-        "fields_all_fields",
-        "fields_example",
-        "fields_add_field",
-        "tags_h",
-        "tags_all_tags",
-        "tags_resources"
-      ]],
-      ["points", [
-        "intro",
-        "add_point_h",
-        "add_point",
-        "add_point_finish",
-        "move_point_h",
-        "move_point",
-        "delete_point_h",
-        "delete_point",
-        "delete_point_command"
-      ]],
-      ["lines", [
-        "intro",
-        "add_line_h",
-        "add_line",
-        "add_line_draw",
-        "add_line_continue",
-        "add_line_finish",
-        "modify_line_h",
-        "modify_line_dragnode",
-        "modify_line_addnode",
-        "connect_line_h",
-        "connect_line",
-        "connect_line_display",
-        "connect_line_drag",
-        "connect_line_tag",
-        "disconnect_line_h",
-        "disconnect_line_command",
-        "move_line_h",
-        "move_line_command",
-        "move_line_connected",
-        "delete_line_h",
-        "delete_line",
-        "delete_line_command"
-      ]],
-      ["areas", [
-        "intro",
-        "point_or_area_h",
-        "point_or_area",
-        "add_area_h",
-        "add_area_command",
-        "add_area_draw",
-        "add_area_continue",
-        "add_area_finish",
-        "square_area_h",
-        "square_area_command",
-        "modify_area_h",
-        "modify_area_dragnode",
-        "modify_area_addnode",
-        "delete_area_h",
-        "delete_area",
-        "delete_area_command"
-      ]],
-      ["relations", [
-        "intro",
-        "edit_relation_h",
-        "edit_relation",
-        "edit_relation_add",
-        "edit_relation_delete",
-        "maintain_relation_h",
-        "maintain_relation",
-        "relation_types_h",
-        "multipolygon_h",
-        "multipolygon",
-        "multipolygon_create",
-        "multipolygon_merge",
-        "turn_restriction_h",
-        "turn_restriction",
-        "turn_restriction_field",
-        "turn_restriction_editing",
-        "route_h",
-        "route",
-        "route_add",
-        "boundary_h",
-        "boundary",
-        "boundary_add"
-      ]],
-      ["operations", [
-        "intro",
-        "intro_2",
-        "straighten",
-        "orthogonalize",
-        "circularize",
-        "move",
-        "rotate",
-        "reflect",
-        "continue",
-        "reverse",
-        "disconnect",
-        "split",
-        "extract",
-        "merge",
-        "delete",
-        "downgrade",
-        "copy_paste"
-      ]],
-      ["notes", [
-        "intro",
-        "add_note_h",
-        "add_note",
-        "place_note",
-        "move_note",
-        "update_note_h",
-        "update_note",
-        "save_note_h",
-        "save_note"
-      ]],
-      ["imagery", [
-        "intro",
-        "sources_h",
-        "choosing",
-        "sources",
-        "offsets_h",
-        "offset",
-        "offset_change"
-      ]],
-      ["streetlevel", [
-        "intro",
-        "using_h",
-        "using",
-        "photos",
-        "viewer"
-      ]],
-      ["gps", [
-        "intro",
-        "survey",
-        "using_h",
-        "using",
-        "tracing",
-        "upload"
-      ]],
-      ["qa", [
-        "intro",
-        "tools_h",
-        "tools",
-        "issues_h",
-        "issues"
-      ]]
-    ];
-    var headings = {
-      "help.help.open_data_h": 3,
-      "help.help.before_start_h": 3,
-      "help.help.open_source_h": 3,
-      "help.overview.navigation_h": 3,
-      "help.overview.features_h": 3,
-      "help.editing.select_h": 3,
-      "help.editing.multiselect_h": 3,
-      "help.editing.undo_redo_h": 3,
-      "help.editing.save_h": 3,
-      "help.editing.upload_h": 3,
-      "help.editing.backups_h": 3,
-      "help.editing.keyboard_h": 3,
-      "help.feature_editor.type_h": 3,
-      "help.feature_editor.fields_h": 3,
-      "help.feature_editor.tags_h": 3,
-      "help.points.add_point_h": 3,
-      "help.points.move_point_h": 3,
-      "help.points.delete_point_h": 3,
-      "help.lines.add_line_h": 3,
-      "help.lines.modify_line_h": 3,
-      "help.lines.connect_line_h": 3,
-      "help.lines.disconnect_line_h": 3,
-      "help.lines.move_line_h": 3,
-      "help.lines.delete_line_h": 3,
-      "help.areas.point_or_area_h": 3,
-      "help.areas.add_area_h": 3,
-      "help.areas.square_area_h": 3,
-      "help.areas.modify_area_h": 3,
-      "help.areas.delete_area_h": 3,
-      "help.relations.edit_relation_h": 3,
-      "help.relations.maintain_relation_h": 3,
-      "help.relations.relation_types_h": 2,
-      "help.relations.multipolygon_h": 3,
-      "help.relations.turn_restriction_h": 3,
-      "help.relations.route_h": 3,
-      "help.relations.boundary_h": 3,
-      "help.notes.add_note_h": 3,
-      "help.notes.update_note_h": 3,
-      "help.notes.save_note_h": 3,
-      "help.imagery.sources_h": 3,
-      "help.imagery.offsets_h": 3,
-      "help.streetlevel.using_h": 3,
-      "help.gps.using_h": 3,
-      "help.qa.tools_h": 3,
-      "help.qa.issues_h": 3
-    };
-    var docs = docKeys.map(function(key) {
-      var helpkey = "help." + key[0];
-      var helpPaneReplacements = { version: context.version };
-      var text2 = key[1].reduce(function(all, part) {
-        var subkey = helpkey + "." + part;
-        var depth = headings[subkey];
-        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
-        return all + hhh + helpHtml(subkey, helpPaneReplacements) + "\n\n";
-      }, "");
-      return {
-        title: _t.html(helpkey + ".title"),
-        content: marked(text2.trim()).replace(/<code>/g, "<kbd>").replace(/<\/code>/g, "</kbd>")
-      };
-    });
-    var helpPane = uiPane("help", context).key(_t("help.key")).label(_t.append("help.title")).description(_t.append("help.title")).iconName("iD-icon-help");
-    helpPane.renderContent = function(content) {
-      function clickHelp(d, i2) {
-        var rtl = _mainLocalizer.textDirection() === "rtl";
-        content.property("scrollTop", 0);
-        helpPane.selection().select(".pane-heading h2").html(d.title);
-        body.html(d.content);
-        body.selectAll("a").attr("target", "_blank");
-        menuItems.classed("selected", function(m) {
-          return m.title === d.title;
-        });
-        nav.html("");
-        if (rtl) {
-          nav.call(drawNext).call(drawPrevious);
-        } else {
-          nav.call(drawPrevious).call(drawNext);
-        }
-        function drawNext(selection2) {
-          if (i2 < docs.length - 1) {
-            var nextLink = selection2.append("a").attr("href", "#").attr("class", "next").on("click", function(d3_event) {
-              d3_event.preventDefault();
-              clickHelp(docs[i2 + 1], i2 + 1);
-            });
-            nextLink.append("span").html(docs[i2 + 1].title).call(svgIcon(rtl ? "#iD-icon-backward" : "#iD-icon-forward", "inline"));
-          }
-        }
-        function drawPrevious(selection2) {
-          if (i2 > 0) {
-            var prevLink = selection2.append("a").attr("href", "#").attr("class", "previous").on("click", function(d3_event) {
-              d3_event.preventDefault();
-              clickHelp(docs[i2 - 1], i2 - 1);
-            });
-            prevLink.call(svgIcon(rtl ? "#iD-icon-forward" : "#iD-icon-backward", "inline")).append("span").html(docs[i2 - 1].title);
-          }
-        }
+  // modules/ui/osmose_details.js
+  function uiOsmoseDetails(context) {
+    let _qaItem;
+    function issueString(d2, type2) {
+      if (!d2) return "";
+      const s2 = services.osmose.getStrings(d2.itemType);
+      return type2 in s2 ? s2[type2] : "";
+    }
+    function osmoseDetails(selection2) {
+      const details = selection2.selectAll(".error-details").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      details.exit().remove();
+      const detailsEnter = details.enter().append("div").attr("class", "error-details qa-details-container");
+      if (issueString(_qaItem, "detail")) {
+        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
+        div.append("h4").call(_t.append("QA.keepRight.detail_description"));
+        div.append("p").attr("class", "qa-details-description-text").html((d2) => issueString(d2, "detail")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
       }
-      function clickWalkthrough(d3_event) {
-        d3_event.preventDefault();
-        if (context.inIntro())
-          return;
-        context.container().call(uiIntro(context));
-        context.ui().togglePanes();
+      const detailsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
+      const elemsDiv = detailsEnter.append("div").attr("class", "qa-details-subsection");
+      if (issueString(_qaItem, "fix")) {
+        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
+        div.append("h4").call(_t.append("QA.osmose.fix_title"));
+        div.append("p").html((d2) => issueString(d2, "fix")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
       }
-      function clickShortcuts(d3_event) {
-        d3_event.preventDefault();
-        context.container().call(context.ui().shortcuts, true);
+      if (issueString(_qaItem, "trap")) {
+        const div = detailsEnter.append("div").attr("class", "qa-details-subsection");
+        div.append("h4").call(_t.append("QA.osmose.trap_title"));
+        div.append("p").html((d2) => issueString(d2, "trap")).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
       }
-      var toc = content.append("ul").attr("class", "toc");
-      var menuItems = toc.selectAll("li").data(docs).enter().append("li").append("a").attr("role", "button").attr("href", "#").html(function(d) {
-        return d.title;
-      }).on("click", function(d3_event, d) {
-        d3_event.preventDefault();
-        clickHelp(d, docs.indexOf(d));
+      const thisItem = _qaItem;
+      services.osmose.loadIssueDetail(_qaItem).then((d2) => {
+        if (!d2.elems || d2.elems.length === 0) return;
+        if (context.selectedErrorID() !== thisItem.id && context.container().selectAll(".qaItem.osmose.hover.itemId-".concat(thisItem.id)).empty()) return;
+        if (d2.detail) {
+          detailsDiv.append("h4").call(_t.append("QA.osmose.detail_title"));
+          detailsDiv.append("p").html((d4) => d4.detail).selectAll("a").attr("rel", "noopener").attr("target", "_blank");
+        }
+        elemsDiv.append("h4").call(_t.append("QA.osmose.elems_title"));
+        elemsDiv.append("ul").selectAll("li").data(d2.elems).enter().append("li").append("a").attr("href", "#").attr("class", "error_entity_link").text((d4) => d4).each(function() {
+          const link3 = select_default2(this);
+          const entityID = this.textContent;
+          const entity = context.hasEntity(entityID);
+          link3.on("mouseenter", () => {
+            utilHighlightEntities([entityID], true, context);
+          }).on("mouseleave", () => {
+            utilHighlightEntities([entityID], false, context);
+          }).on("click", (d3_event) => {
+            d3_event.preventDefault();
+            utilHighlightEntities([entityID], false, context);
+            const osmlayer = context.layers().layer("osm");
+            if (!osmlayer.enabled()) {
+              osmlayer.enabled(true);
+            }
+            context.map().centerZoom(d2.loc, 20);
+            if (entity) {
+              context.enter(modeSelect(context, [entityID]));
+            } else {
+              context.loadEntity(entityID, (err, result) => {
+                if (err) return;
+                const entity2 = result.data.find((e3) => e3.id === entityID);
+                if (entity2) context.enter(modeSelect(context, [entityID]));
+              });
+            }
+          });
+          if (entity) {
+            let name = utilDisplayName(entity);
+            if (!name) {
+              const preset = _mainPresetIndex.match(entity, context.graph());
+              name = preset && !preset.isFallback() && preset.name();
+            }
+            if (name) {
+              this.innerText = name;
+            }
+          }
+        });
+        context.features().forceVisible(d2.elems);
+        context.map().pan([0, 0]);
+      }).catch((err) => {
+        console.log(err);
       });
-      var shortcuts = toc.append("li").attr("class", "shortcuts").call(
-        uiTooltip().title(() => _t.append("shortcuts.tooltip")).keys(["?"]).placement("top")
-      ).append("a").attr("href", "#").on("click", clickShortcuts);
-      shortcuts.append("div").call(_t.append("shortcuts.title"));
-      var walkthrough = toc.append("li").attr("class", "walkthrough").append("a").attr("href", "#").on("click", clickWalkthrough);
-      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
-      walkthrough.append("div").call(_t.append("splash.walkthrough"));
-      var helpContent = content.append("div").attr("class", "left-content");
-      var body = helpContent.append("div").attr("class", "body");
-      var nav = helpContent.append("div").attr("class", "nav");
-      clickHelp(docs[0], 0);
+    }
+    osmoseDetails.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return osmoseDetails;
     };
-    return helpPane;
+    return osmoseDetails;
   }
 
-  // modules/ui/sections/validation_issues.js
-  function uiSectionValidationIssues(id2, severity, context) {
-    var _issues = [];
-    var section = uiSection(id2, context).label(function() {
-      if (!_issues)
-        return "";
-      var issueCountText = _issues.length > 1e3 ? "1000+" : String(_issues.length);
-      return _t.append("inspector.title_count", { title: _t("issues." + severity + "s.list_title"), count: issueCountText });
-    }).disclosureContent(renderDisclosureContent).shouldDisplay(function() {
-      return _issues && _issues.length;
-    });
-    function getOptions() {
-      return {
-        what: corePreferences("validate-what") || "edited",
-        where: corePreferences("validate-where") || "all"
-      };
-    }
-    function reloadIssues() {
-      _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
-    }
-    function renderDisclosureContent(selection2) {
-      var center = context.map().center();
-      var graph = context.graph();
-      var issues = _issues.map(function withDistance(issue) {
-        var extent = issue.extent(graph);
-        var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
-        return Object.assign(issue, { dist });
-      }).sort(function byDistance(a, b) {
-        return a.dist - b.dist;
-      });
-      issues = issues.slice(0, 1e3);
-      selection2.call(drawIssuesList, issues);
+  // modules/ui/osmose_header.js
+  function uiOsmoseHeader() {
+    let _qaItem;
+    function issueTitle(d2) {
+      const unknown = _t("inspector.unknown");
+      if (!d2) return unknown;
+      const s2 = services.osmose.getStrings(d2.itemType);
+      return "title" in s2 ? s2.title : unknown;
     }
-    function drawIssuesList(selection2, issues) {
-      var list = selection2.selectAll(".issues-list").data([0]);
-      list = list.enter().append("ul").attr("class", "layer-list issues-list " + severity + "s-list").merge(list);
-      var items = list.selectAll("li").data(issues, function(d) {
-        return d.key;
-      });
-      items.exit().remove();
-      var itemsEnter = items.enter().append("li").attr("class", function(d) {
-        return "issue severity-" + d.severity;
-      });
-      var labelsEnter = itemsEnter.append("button").attr("class", "issue-label").on("click", function(d3_event, d) {
-        context.validator().focusIssue(d);
-      }).on("mouseover", function(d3_event, d) {
-        utilHighlightEntities(d.entityIds, true, context);
-      }).on("mouseout", function(d3_event, d) {
-        utilHighlightEntities(d.entityIds, false, context);
-      });
-      var textEnter = labelsEnter.append("span").attr("class", "issue-text");
-      textEnter.append("span").attr("class", "issue-icon").each(function(d) {
-        var iconName = "#iD-icon-" + (d.severity === "warning" ? "alert" : "error");
-        select_default2(this).call(svgIcon(iconName));
-      });
-      textEnter.append("span").attr("class", "issue-message");
-      items = items.merge(itemsEnter).order();
-      items.selectAll(".issue-message").text("").each(function(d) {
-        return d.message(context)(select_default2(this));
-      });
+    function osmoseHeader(selection2) {
+      const header = selection2.selectAll(".qa-header").data(
+        _qaItem ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      header.exit().remove();
+      const headerEnter = header.enter().append("div").attr("class", "qa-header");
+      const svgEnter = headerEnter.append("div").attr("class", "qa-header-icon").classed("new", (d2) => d2.id < 0).append("svg").attr("width", "20px").attr("height", "30px").attr("viewbox", "0 0 20 30").attr("class", (d2) => "preset-icon-28 qaItem ".concat(d2.service, " itemId-").concat(d2.id, " itemType-").concat(d2.itemType));
+      svgEnter.append("polygon").attr("fill", (d2) => services.osmose.getColor(d2.item)).attr("class", "qaItem-fill").attr("points", "16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6");
+      svgEnter.append("use").attr("class", "icon-annotation").attr("width", "12px").attr("height", "12px").attr("transform", "translate(4, 5.5)").attr("xlink:href", (d2) => d2.icon ? "#" + d2.icon : "");
+      headerEnter.append("div").attr("class", "qa-header-label").text(issueTitle);
     }
-    context.validator().on("validated.uiSectionValidationIssues" + id2, function() {
-      window.requestIdleCallback(function() {
-        reloadIssues();
-        section.reRender();
-      });
-    });
-    context.map().on(
-      "move.uiSectionValidationIssues" + id2,
-      debounce_default(function() {
-        window.requestIdleCallback(function() {
-          if (getOptions().where === "visible") {
-            reloadIssues();
-          }
-          section.reRender();
-        });
-      }, 1e3)
-    );
-    return section;
+    osmoseHeader.issue = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return osmoseHeader;
+    };
+    return osmoseHeader;
   }
 
-  // modules/ui/sections/validation_options.js
-  function uiSectionValidationOptions(context) {
-    var section = uiSection("issues-options", context).content(renderContent);
-    function renderContent(selection2) {
-      var container = selection2.selectAll(".issues-options-container").data([0]);
-      container = container.enter().append("div").attr("class", "issues-options-container").merge(container);
-      var data = [
-        { key: "what", values: ["edited", "all"] },
-        { key: "where", values: ["visible", "all"] }
-      ];
-      var options2 = container.selectAll(".issues-option").data(data, function(d) {
-        return d.key;
-      });
-      var optionsEnter = options2.enter().append("div").attr("class", function(d) {
-        return "issues-option issues-option-" + d.key;
-      });
-      optionsEnter.append("div").attr("class", "issues-option-title").html(function(d) {
-        return _t.html("issues.options." + d.key + ".title");
-      });
-      var valuesEnter = optionsEnter.selectAll("label").data(function(d) {
-        return d.values.map(function(val) {
-          return { value: val, key: d.key };
-        });
-      }).enter().append("label");
-      valuesEnter.append("input").attr("type", "radio").attr("name", function(d) {
-        return "issues-option-" + d.key;
-      }).attr("value", function(d) {
-        return d.value;
-      }).property("checked", function(d) {
-        return getOptions()[d.key] === d.value;
-      }).on("change", function(d3_event, d) {
-        updateOptionValue(d3_event, d.key, d.value);
-      });
-      valuesEnter.append("span").html(function(d) {
-        return _t.html("issues.options." + d.key + "." + d.value);
-      });
-    }
-    function getOptions() {
-      return {
-        what: corePreferences("validate-what") || "edited",
-        where: corePreferences("validate-where") || "all"
-      };
-    }
-    function updateOptionValue(d3_event, d, val) {
-      if (!val && d3_event && d3_event.target) {
-        val = d3_event.target.value;
+  // modules/ui/view_on_osmose.js
+  function uiViewOnOsmose() {
+    let _qaItem;
+    function viewOnOsmose(selection2) {
+      let url;
+      if (services.osmose && _qaItem instanceof QAItem) {
+        url = services.osmose.itemURL(_qaItem);
       }
-      corePreferences("validate-" + d, val);
-      context.validator().validate();
+      const link3 = selection2.selectAll(".view-on-osmose").data(url ? [url] : []);
+      link3.exit().remove();
+      const linkEnter = link3.enter().append("a").attr("class", "view-on-osmose").attr("target", "_blank").attr("rel", "noopener").attr("href", (d2) => d2).call(svgIcon("#iD-icon-out-link", "inline"));
+      linkEnter.append("span").call(_t.append("inspector.view_on_osmose"));
     }
-    return section;
+    viewOnOsmose.what = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return viewOnOsmose;
+    };
+    return viewOnOsmose;
   }
 
-  // modules/ui/sections/validation_rules.js
-  function uiSectionValidationRules(context) {
-    var MINSQUARE = 0;
-    var MAXSQUARE = 20;
-    var DEFAULTSQUARE = 5;
-    var section = uiSection("issues-rules", context).disclosureContent(renderDisclosureContent).label(() => _t.append("issues.rules.title"));
-    var _ruleKeys = context.validator().getRuleKeys().filter(function(key) {
-      return key !== "maprules";
-    }).sort(function(key1, key2) {
-      return _t("issues." + key1 + ".title") < _t("issues." + key2 + ".title") ? -1 : 1;
-    });
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".issues-rulelist-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "issues-rulelist-container");
-      containerEnter.append("ul").attr("class", "layer-list issue-rules-list");
-      var ruleLinks = containerEnter.append("div").attr("class", "issue-rules-links section-footer");
-      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.validator().disableRules(_ruleKeys);
-      });
-      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.validator().disableRules([]);
-      });
-      container = container.merge(containerEnter);
-      container.selectAll(".issue-rules-list").call(drawListItems, _ruleKeys, "checkbox", "rule", toggleRule, isRuleEnabled);
+  // modules/ui/osmose_editor.js
+  function uiOsmoseEditor(context) {
+    const dispatch14 = dispatch_default("change");
+    const qaDetails = uiOsmoseDetails(context);
+    const qaHeader = uiOsmoseHeader(context);
+    let _qaItem;
+    function osmoseEditor(selection2) {
+      const header = selection2.selectAll(".header").data([0]);
+      const headerEnter = header.enter().append("div").attr("class", "header fillL");
+      headerEnter.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => context.enter(modeBrowse(context))).call(svgIcon("#iD-icon-close"));
+      headerEnter.append("h2").call(_t.append("QA.osmose.title"));
+      let body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      let editor = body.selectAll(".qa-editor").data([0]);
+      editor.enter().append("div").attr("class", "modal-section qa-editor").merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
+      const footer = selection2.selectAll(".footer").data([0]);
+      footer.enter().append("div").attr("class", "footer").merge(footer).call(uiViewOnOsmose(context).what(_qaItem));
     }
-    function drawListItems(selection2, data, type3, name, change, active) {
-      var items = selection2.selectAll("li").data(data);
-      items.exit().remove();
-      var enter = items.enter().append("li");
-      if (name === "rule") {
-        enter.call(
-          uiTooltip().title(function(d) {
-            return _t.append("issues." + d + ".tip");
-          }).placement("top")
-        );
-      }
-      var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", name).on("change", change);
-      label.append("span").html(function(d) {
-        var params = {};
-        if (d === "unsquare_way") {
-          params.val = { html: '<span class="square-degrees"></span>' };
+    function osmoseSaveSection(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      const isShown = _qaItem && isSelected;
+      let saveSection = selection2.selectAll(".qa-save").data(
+        isShown ? [_qaItem] : [],
+        (d2) => "".concat(d2.id, "-").concat(d2.status || 0)
+      );
+      saveSection.exit().remove();
+      const saveSectionEnter = saveSection.enter().append("div").attr("class", "qa-save save-section cf");
+      saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
+    }
+    function qaSaveButtons(selection2) {
+      const isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
+      let buttonSection = selection2.selectAll(".buttons").data(isSelected ? [_qaItem] : [], (d2) => d2.status + d2.id);
+      buttonSection.exit().remove();
+      const buttonEnter = buttonSection.enter().append("div").attr("class", "buttons");
+      buttonEnter.append("button").attr("class", "button close-button action");
+      buttonEnter.append("button").attr("class", "button ignore-button action");
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.select(".close-button").call(_t.append("QA.keepRight.close")).on("click.close", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.osmose;
+        if (qaService) {
+          d2.newStatus = "done";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
         }
-        return _t.html("issues." + d + ".title", params);
       });
-      items = items.merge(enter);
-      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
-      var degStr = corePreferences("validate-square-degrees");
-      if (degStr === null) {
-        degStr = DEFAULTSQUARE.toString();
-      }
-      var span = items.selectAll(".square-degrees");
-      var input = span.selectAll(".square-degrees-input").data([0]);
-      input.enter().append("input").attr("type", "number").attr("min", MINSQUARE.toString()).attr("max", MAXSQUARE.toString()).attr("step", "0.5").attr("class", "square-degrees-input").call(utilNoAuto).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        this.select();
-      }).on("keyup", function(d3_event) {
-        if (d3_event.keyCode === 13) {
-          this.blur();
-          this.select();
+      buttonSection.select(".ignore-button").call(_t.append("QA.keepRight.ignore")).on("click.ignore", function(d3_event, d2) {
+        this.blur();
+        const qaService = services.osmose;
+        if (qaService) {
+          d2.newStatus = "false";
+          qaService.postUpdate(d2, (err, item) => dispatch14.call("change", item));
         }
-      }).on("blur", changeSquare).merge(input).property("value", degStr);
-    }
-    function changeSquare() {
-      var input = select_default2(this);
-      var degStr = utilGetSetValue(input).trim();
-      var degNum = parseFloat(degStr, 10);
-      if (!isFinite(degNum)) {
-        degNum = DEFAULTSQUARE;
-      } else if (degNum > MAXSQUARE) {
-        degNum = MAXSQUARE;
-      } else if (degNum < MINSQUARE) {
-        degNum = MINSQUARE;
-      }
-      degNum = Math.round(degNum * 10) / 10;
-      degStr = degNum.toString();
-      input.property("value", degStr);
-      corePreferences("validate-square-degrees", degStr);
-      context.validator().revalidateUnsquare();
-    }
-    function isRuleEnabled(d) {
-      return context.validator().isRuleEnabled(d);
-    }
-    function toggleRule(d3_event, d) {
-      context.validator().toggleRule(d);
+      });
     }
-    context.validator().on("validated.uiSectionValidationRules", function() {
-      window.requestIdleCallback(section.reRender);
-    });
-    return section;
+    osmoseEditor.error = function(val) {
+      if (!arguments.length) return _qaItem;
+      _qaItem = val;
+      return osmoseEditor;
+    };
+    return utilRebind(osmoseEditor, dispatch14, "on");
   }
 
-  // modules/ui/sections/validation_status.js
-  function uiSectionValidationStatus(context) {
-    var section = uiSection("issues-status", context).content(renderContent).shouldDisplay(function() {
-      var issues = context.validator().getIssues(getOptions());
-      return issues.length === 0;
-    });
-    function getOptions() {
-      return {
-        what: corePreferences("validate-what") || "edited",
-        where: corePreferences("validate-where") || "all"
-      };
-    }
-    function renderContent(selection2) {
-      var box = selection2.selectAll(".box").data([0]);
-      var boxEnter = box.enter().append("div").attr("class", "box");
-      boxEnter.append("div").call(svgIcon("#iD-icon-apply", "pre-text"));
-      var noIssuesMessage = boxEnter.append("span");
-      noIssuesMessage.append("strong").attr("class", "message");
-      noIssuesMessage.append("br");
-      noIssuesMessage.append("span").attr("class", "details");
-      renderIgnoredIssuesReset(selection2);
-      setNoIssuesText(selection2);
-    }
-    function renderIgnoredIssuesReset(selection2) {
-      var ignoredIssues = context.validator().getIssues({ what: "all", where: "all", includeDisabledRules: true, includeIgnored: "only" });
-      var resetIgnored = selection2.selectAll(".reset-ignored").data(ignoredIssues.length ? [0] : []);
-      resetIgnored.exit().remove();
-      var resetIgnoredEnter = resetIgnored.enter().append("div").attr("class", "reset-ignored section-footer");
-      resetIgnoredEnter.append("a").attr("href", "#");
-      resetIgnored = resetIgnored.merge(resetIgnoredEnter);
-      resetIgnored.select("a").html(_t.html("inspector.title_count", { title: { html: _t.html("issues.reset_ignored") }, count: ignoredIssues.length }));
-      resetIgnored.on("click", function(d3_event) {
+  // modules/ui/sidebar.js
+  function uiSidebar(context) {
+    var inspector = uiInspector(context);
+    var dataEditor = uiDataEditor(context);
+    var noteEditor = uiNoteEditor(context);
+    var keepRightEditor = uiKeepRightEditor(context);
+    var osmoseEditor = uiOsmoseEditor(context);
+    var _current;
+    var _wasData = false;
+    var _wasNote = false;
+    var _wasQaItem = false;
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    function sidebar(selection2) {
+      var container = context.container();
+      var minWidth = 240;
+      var sidebarWidth;
+      var containerWidth;
+      var dragOffset;
+      selection2.style("min-width", minWidth + "px").style("max-width", "400px").style("width", "33.3333%");
+      var resizer = selection2.append("div").attr("class", "sidebar-resizer").on(_pointerPrefix + "down.sidebar-resizer", pointerdown);
+      var downPointerId, lastClientX, containerLocGetter;
+      function pointerdown(d3_event) {
+        if (downPointerId) return;
+        if ("button" in d3_event && d3_event.button !== 0) return;
+        downPointerId = d3_event.pointerId || "mouse";
+        lastClientX = d3_event.clientX;
+        containerLocGetter = utilFastMouse(container.node());
+        dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
+        sidebarWidth = selection2.node().getBoundingClientRect().width;
+        containerWidth = container.node().getBoundingClientRect().width;
+        var widthPct = sidebarWidth / containerWidth * 100;
+        selection2.style("width", widthPct + "%").style("max-width", "85%");
+        resizer.classed("dragging", true);
+        select_default2(window).on("touchmove.sidebar-resizer", function(d3_event2) {
+          d3_event2.preventDefault();
+        }, { passive: false }).on(_pointerPrefix + "move.sidebar-resizer", pointermove).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", pointerup);
+      }
+      function pointermove(d3_event) {
+        if (downPointerId !== (d3_event.pointerId || "mouse")) return;
         d3_event.preventDefault();
-        context.validator().resetIgnoredIssues();
-      });
-    }
-    function setNoIssuesText(selection2) {
-      var opts = getOptions();
-      function checkForHiddenIssues(cases) {
-        for (var type3 in cases) {
-          var hiddenOpts = cases[type3];
-          var hiddenIssues = context.validator().getIssues(hiddenOpts);
-          if (hiddenIssues.length) {
-            selection2.select(".box .details").html("").call(_t.append(
-              "issues.no_issues.hidden_issues." + type3,
-              { count: hiddenIssues.length.toString() }
-            ));
-            return;
+        var dx = d3_event.clientX - lastClientX;
+        lastClientX = d3_event.clientX;
+        var isRTL = _mainLocalizer.textDirection() === "rtl";
+        var scaleX = isRTL ? 0 : 1;
+        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
+        var x2 = containerLocGetter(d3_event)[0] - dragOffset;
+        sidebarWidth = isRTL ? containerWidth - x2 : x2;
+        var isCollapsed = selection2.classed("collapsed");
+        var shouldCollapse = sidebarWidth < minWidth;
+        selection2.classed("collapsed", shouldCollapse);
+        if (shouldCollapse) {
+          if (!isCollapsed) {
+            selection2.style(xMarginProperty, "-400px").style("width", "400px");
+            context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
+          }
+        } else {
+          var widthPct = sidebarWidth / containerWidth * 100;
+          selection2.style(xMarginProperty, null).style("width", widthPct + "%");
+          if (isCollapsed) {
+            context.ui().onResize([-sidebarWidth * scaleX, 0]);
+          } else {
+            context.ui().onResize([-dx * scaleX, 0]);
           }
         }
-        selection2.select(".box .details").html("").call(_t.append("issues.no_issues.hidden_issues.none"));
       }
-      var messageType;
-      if (opts.what === "edited" && opts.where === "visible") {
-        messageType = "edits_in_view";
-        checkForHiddenIssues({
-          elsewhere: { what: "edited", where: "all" },
-          everything_else: { what: "all", where: "visible" },
-          disabled_rules: { what: "edited", where: "visible", includeDisabledRules: "only" },
-          everything_else_elsewhere: { what: "all", where: "all" },
-          disabled_rules_elsewhere: { what: "edited", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "edited", where: "visible", includeIgnored: "only" },
-          ignored_issues_elsewhere: { what: "edited", where: "all", includeIgnored: "only" }
-        });
-      } else if (opts.what === "edited" && opts.where === "all") {
-        messageType = "edits";
-        checkForHiddenIssues({
-          everything_else: { what: "all", where: "all" },
-          disabled_rules: { what: "edited", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "edited", where: "all", includeIgnored: "only" }
-        });
-      } else if (opts.what === "all" && opts.where === "visible") {
-        messageType = "everything_in_view";
-        checkForHiddenIssues({
-          elsewhere: { what: "all", where: "all" },
-          disabled_rules: { what: "all", where: "visible", includeDisabledRules: "only" },
-          disabled_rules_elsewhere: { what: "all", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "all", where: "visible", includeIgnored: "only" },
-          ignored_issues_elsewhere: { what: "all", where: "all", includeIgnored: "only" }
-        });
-      } else if (opts.what === "all" && opts.where === "all") {
-        messageType = "everything";
-        checkForHiddenIssues({
-          disabled_rules: { what: "all", where: "all", includeDisabledRules: "only" },
-          ignored_issues: { what: "all", where: "all", includeIgnored: "only" }
-        });
+      function pointerup(d3_event) {
+        if (downPointerId !== (d3_event.pointerId || "mouse")) return;
+        downPointerId = null;
+        resizer.classed("dragging", false);
+        select_default2(window).on("touchmove.sidebar-resizer", null).on(_pointerPrefix + "move.sidebar-resizer", null).on(_pointerPrefix + "up.sidebar-resizer pointercancel.sidebar-resizer", null);
       }
-      if (opts.what === "edited" && context.history().difference().summary().length === 0) {
-        messageType = "no_edits";
+      var featureListWrap = selection2.append("div").attr("class", "feature-list-pane").call(uiFeatureList(context));
+      var inspectorWrap = selection2.append("div").attr("class", "inspector-hidden inspector-wrap");
+      var hoverModeSelect = function(targets) {
+        context.container().selectAll(".feature-list-item button").classed("hover", false);
+        if (context.selectedIDs().length > 1 && targets && targets.length) {
+          var elements = context.container().selectAll(".feature-list-item button").filter(function(node) {
+            return targets.indexOf(node) !== -1;
+          });
+          if (!elements.empty()) {
+            elements.classed("hover", true);
+          }
+        }
+      };
+      sidebar.hoverModeSelect = throttle_default(hoverModeSelect, 200);
+      function hover(targets) {
+        var datum2 = targets && targets.length && targets[0];
+        if (datum2 && datum2.__featurehash__) {
+          _wasData = true;
+          sidebar.show(dataEditor.datum(datum2));
+          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
+        } else if (datum2 instanceof osmNote) {
+          if (context.mode().id === "drag-note") return;
+          _wasNote = true;
+          var osm = services.osm;
+          if (osm) {
+            datum2 = osm.getNote(datum2.id);
+          }
+          sidebar.show(noteEditor.note(datum2));
+          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
+        } else if (datum2 instanceof QAItem) {
+          _wasQaItem = true;
+          var errService = services[datum2.service];
+          if (errService) {
+            datum2 = errService.getError(datum2.id);
+          }
+          var errEditor;
+          if (datum2.service === "keepRight") {
+            errEditor = keepRightEditor;
+          } else {
+            errEditor = osmoseEditor;
+          }
+          context.container().selectAll(".qaItem." + datum2.service).classed("hover", function(d2) {
+            return d2.id === datum2.id;
+          });
+          sidebar.show(errEditor.error(datum2));
+          selection2.selectAll(".sidebar-component").classed("inspector-hover", true);
+        } else if (!_current && datum2 instanceof osmEntity) {
+          featureListWrap.classed("inspector-hidden", true);
+          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", true);
+          if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum2.id]) || inspector.state() !== "hover") {
+            inspector.state("hover").entityIDs([datum2.id]).newFeature(false);
+            inspectorWrap.call(inspector);
+          }
+        } else if (!_current) {
+          featureListWrap.classed("inspector-hidden", false);
+          inspectorWrap.classed("inspector-hidden", true);
+          inspector.state("hide");
+        } else if (_wasData || _wasNote || _wasQaItem) {
+          _wasNote = false;
+          _wasData = false;
+          _wasQaItem = false;
+          context.container().selectAll(".note").classed("hover", false);
+          context.container().selectAll(".qaItem").classed("hover", false);
+          sidebar.hide();
+        }
       }
-      selection2.select(".box .message").html("").call(_t.append("issues.no_issues.message." + messageType));
-    }
-    context.validator().on("validated.uiSectionValidationStatus", function() {
-      window.requestIdleCallback(section.reRender);
-    });
-    context.map().on(
-      "move.uiSectionValidationStatus",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
-  }
-
-  // modules/ui/panes/issues.js
-  function uiPaneIssues(context) {
-    var issuesPane = uiPane("issues", context).key(_t("issues.key")).label(_t.append("issues.title")).description(_t.append("issues.title")).iconName("iD-icon-alert").sections([
-      uiSectionValidationOptions(context),
-      uiSectionValidationStatus(context),
-      uiSectionValidationIssues("issues-errors", "error", context),
-      uiSectionValidationIssues("issues-warnings", "warning", context),
-      uiSectionValidationRules(context)
-    ]);
-    return issuesPane;
-  }
-
-  // modules/ui/settings/custom_data.js
-  function uiSettingsCustomData(context) {
-    var dispatch10 = dispatch_default("change");
-    function render(selection2) {
-      var dataLayer = context.layers().layer("data");
-      var _origSettings = {
-        fileList: dataLayer && dataLayer.fileList() || null,
-        url: corePreferences("settings-custom-data-url")
+      sidebar.hover = throttle_default(hover, 200);
+      sidebar.intersects = function(extent) {
+        var rect = selection2.node().getBoundingClientRect();
+        return extent.intersects([
+          context.projection.invert([0, rect.height]),
+          context.projection.invert([rect.width, 0])
+        ]);
       };
-      var _currSettings = {
-        fileList: dataLayer && dataLayer.fileList() || null,
-        url: corePreferences("settings-custom-data-url")
+      sidebar.select = function(ids, newFeature) {
+        sidebar.hide();
+        if (ids && ids.length) {
+          var entity = ids.length === 1 && context.entity(ids[0]);
+          if (entity && newFeature && selection2.classed("collapsed")) {
+            var extent = entity.extent(context.graph());
+            sidebar.expand(sidebar.intersects(extent));
+          }
+          featureListWrap.classed("inspector-hidden", true);
+          inspectorWrap.classed("inspector-hidden", false).classed("inspector-hover", false);
+          inspector.state("select").entityIDs(ids).newFeature(newFeature);
+          inspectorWrap.call(inspector);
+        } else {
+          inspector.state("hide");
+        }
       };
-      var modal = uiConfirm(selection2).okButton();
-      modal.classed("settings-modal settings-custom-data", true);
-      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_data.header"));
-      var textSection = modal.select(".modal-section.message-text");
-      textSection.append("pre").attr("class", "instructions-file").call(_t.append("settings.custom_data.file.instructions"));
-      textSection.append("input").attr("class", "field-file").attr("type", "file").attr("accept", ".gpx,.kml,.geojson,.json,application/gpx+xml,application/vnd.google-earth.kml+xml,application/geo+json,application/json").property("files", _currSettings.fileList).on("change", function(d3_event) {
-        var files = d3_event.target.files;
-        if (files && files.length) {
-          _currSettings.url = "";
-          textSection.select(".field-url").property("value", "");
-          _currSettings.fileList = files;
+      sidebar.showPresetList = function() {
+        inspector.showList();
+      };
+      sidebar.show = function(component, element) {
+        featureListWrap.classed("inspector-hidden", true);
+        inspectorWrap.classed("inspector-hidden", true);
+        if (_current) _current.remove();
+        _current = selection2.append("div").attr("class", "sidebar-component").call(component, element);
+      };
+      sidebar.hide = function() {
+        featureListWrap.classed("inspector-hidden", false);
+        inspectorWrap.classed("inspector-hidden", true);
+        if (_current) _current.remove();
+        _current = null;
+      };
+      sidebar.expand = function(moveMap) {
+        if (selection2.classed("collapsed")) {
+          sidebar.toggle(moveMap);
+        }
+      };
+      sidebar.collapse = function(moveMap) {
+        if (!selection2.classed("collapsed")) {
+          sidebar.toggle(moveMap);
+        }
+      };
+      sidebar.toggle = function(moveMap) {
+        if (context.inIntro()) return;
+        var isCollapsed = selection2.classed("collapsed");
+        var isCollapsing = !isCollapsed;
+        var isRTL = _mainLocalizer.textDirection() === "rtl";
+        var scaleX = isRTL ? 0 : 1;
+        var xMarginProperty = isRTL ? "margin-right" : "margin-left";
+        sidebarWidth = selection2.node().getBoundingClientRect().width;
+        selection2.style("width", sidebarWidth + "px");
+        var startMargin, endMargin, lastMargin;
+        if (isCollapsing) {
+          startMargin = lastMargin = 0;
+          endMargin = -sidebarWidth;
         } else {
-          _currSettings.fileList = null;
+          startMargin = lastMargin = -sidebarWidth;
+          endMargin = 0;
         }
-      });
-      textSection.append("h4").call(_t.append("settings.custom_data.or"));
-      textSection.append("pre").attr("class", "instructions-url").call(_t.append("settings.custom_data.url.instructions"));
-      textSection.append("textarea").attr("class", "field-url").attr("placeholder", _t("settings.custom_data.url.placeholder")).call(utilNoAuto).property("value", _currSettings.url);
-      var buttonSection = modal.select(".modal-section.buttons");
-      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
-      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
-      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
-      function isSaveDisabled() {
-        return null;
-      }
-      function clickCancel() {
-        textSection.select(".field-url").property("value", _origSettings.url);
-        corePreferences("settings-custom-data-url", _origSettings.url);
-        this.blur();
-        modal.close();
-      }
-      function clickSave() {
-        _currSettings.url = textSection.select(".field-url").property("value").trim();
-        if (_currSettings.url) {
-          _currSettings.fileList = null;
+        if (!isCollapsing) {
+          selection2.classed("collapsed", isCollapsing);
         }
-        if (_currSettings.fileList) {
-          _currSettings.url = "";
+        selection2.transition().style(xMarginProperty, endMargin + "px").tween("panner", function() {
+          var i3 = number_default(startMargin, endMargin);
+          return function(t2) {
+            var dx = lastMargin - Math.round(i3(t2));
+            lastMargin = lastMargin - dx;
+            context.ui().onResize(moveMap ? void 0 : [dx * scaleX, 0]);
+          };
+        }).on("end", function() {
+          if (isCollapsing) {
+            selection2.classed("collapsed", isCollapsing);
+          }
+          if (!isCollapsing) {
+            var containerWidth2 = container.node().getBoundingClientRect().width;
+            var widthPct = sidebarWidth / containerWidth2 * 100;
+            selection2.style(xMarginProperty, null).style("width", widthPct + "%");
+          }
+        });
+      };
+      resizer.on("dblclick", function(d3_event) {
+        d3_event.preventDefault();
+        if (d3_event.sourceEvent) {
+          d3_event.sourceEvent.preventDefault();
         }
-        corePreferences("settings-custom-data-url", _currSettings.url);
-        this.blur();
-        modal.close();
-        dispatch10.call("change", this, _currSettings);
-      }
+        sidebar.toggle();
+      });
+      context.map().on("crossEditableZoom.sidebar", function(within) {
+        if (!within && !selection2.select(".inspector-hover").empty()) {
+          hover([]);
+        }
+      });
     }
-    return utilRebind(render, dispatch10, "on");
+    sidebar.showPresetList = function() {
+    };
+    sidebar.hover = function() {
+    };
+    sidebar.hover.cancel = function() {
+    };
+    sidebar.intersects = function() {
+    };
+    sidebar.select = function() {
+    };
+    sidebar.show = function() {
+    };
+    sidebar.hide = function() {
+    };
+    sidebar.expand = function() {
+    };
+    sidebar.collapse = function() {
+    };
+    sidebar.toggle = function() {
+    };
+    return sidebar;
   }
 
-  // modules/ui/sections/data_layers.js
-  function uiSectionDataLayers(context) {
-    var settingsCustomData = uiSettingsCustomData(context).on("change", customChanged);
-    var layers = context.layers();
-    var section = uiSection("data-layers", context).label(() => _t.append("map_data.data_layers")).disclosureContent(renderDisclosureContent);
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".data-layer-container").data([0]);
-      container.enter().append("div").attr("class", "data-layer-container").merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems).call(drawPanelItems);
+  // modules/ui/source_switch.js
+  function uiSourceSwitch(context) {
+    var keys2;
+    function click(d3_event) {
+      d3_event.preventDefault();
+      var osm = context.connection();
+      if (!osm) return;
+      if (context.inIntro()) return;
+      if (context.history().hasChanges() && !window.confirm(_t("source_switch.lose_changes"))) return;
+      var isLive = select_default2(this).classed("live");
+      isLive = !isLive;
+      context.enter(modeBrowse(context));
+      context.history().clearSaved();
+      context.flush();
+      select_default2(this).html(isLive ? _t.html("source_switch.live") : _t.html("source_switch.dev")).classed("live", isLive).classed("chip", isLive);
+      osm.switch(isLive ? keys2[0] : keys2[1]);
     }
-    function showsLayer(which) {
-      var layer = layers.layer(which);
-      if (layer) {
-        return layer.enabled();
+    var sourceSwitch = function(selection2) {
+      selection2.append("a").attr("href", "#").call(_t.append("source_switch.live")).attr("class", "live chip").on("click", click);
+    };
+    sourceSwitch.keys = function(_2) {
+      if (!arguments.length) return keys2;
+      keys2 = _2;
+      return sourceSwitch;
+    };
+    return sourceSwitch;
+  }
+
+  // modules/ui/spinner.js
+  function uiSpinner(context) {
+    var osm = context.connection();
+    return function(selection2) {
+      var img = selection2.append("img").attr("src", context.imagePath("loader-black.gif")).style("opacity", 0);
+      if (osm) {
+        osm.on("loading.spinner", function() {
+          img.transition().style("opacity", 1);
+        }).on("loaded.spinner", function() {
+          img.transition().style("opacity", 0);
+        });
       }
-      return false;
+    };
+  }
+
+  // modules/ui/sections/privacy.js
+  function uiSectionPrivacy(context) {
+    let section = uiSection("preferences-third-party", context).label(() => _t.append("preferences.privacy.title")).disclosureContent(renderDisclosureContent);
+    function renderDisclosureContent(selection2) {
+      selection2.selectAll(".privacy-options-list").data([0]).enter().append("ul").attr("class", "layer-list privacy-options-list");
+      let thirdPartyIconsEnter = selection2.select(".privacy-options-list").selectAll(".privacy-third-party-icons-item").data([corePreferences("preferences.privacy.thirdpartyicons") || "true"]).enter().append("li").attr("class", "privacy-third-party-icons-item").append("label").call(
+        uiTooltip().title(() => _t.append("preferences.privacy.third_party_icons.tooltip")).placement("bottom")
+      );
+      thirdPartyIconsEnter.append("input").attr("type", "checkbox").on("change", (d3_event, d2) => {
+        d3_event.preventDefault();
+        corePreferences("preferences.privacy.thirdpartyicons", d2 === "true" ? "false" : "true");
+      });
+      thirdPartyIconsEnter.append("span").call(_t.append("preferences.privacy.third_party_icons.description"));
+      selection2.selectAll(".privacy-third-party-icons-item").classed("active", (d2) => d2 === "true").select("input").property("checked", (d2) => d2 === "true");
+      selection2.selectAll(".privacy-link").data([0]).enter().append("div").attr("class", "privacy-link").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/release/PRIVACY.md").append("span").call(_t.append("preferences.privacy.privacy_link"));
     }
-    function setLayer(which, enabled) {
-      var mode = context.mode();
-      if (mode && /^draw/.test(mode.id))
-        return;
-      var layer = layers.layer(which);
-      if (layer) {
-        layer.enabled(enabled);
-        if (!enabled && (which === "osm" || which === "notes")) {
-          context.enter(modeBrowse(context));
-        }
+    corePreferences.onChange("preferences.privacy.thirdpartyicons", section.reRender);
+    return section;
+  }
+
+  // modules/ui/splash.js
+  function uiSplash(context) {
+    return (selection2) => {
+      if (context.history().hasRestorableChanges()) return;
+      let updateMessage = "";
+      const sawPrivacyVersion = corePreferences("sawPrivacyVersion");
+      let showSplash = !corePreferences("sawSplash");
+      if (sawPrivacyVersion !== context.privacyVersion) {
+        updateMessage = _t("splash.privacy_update");
+        showSplash = true;
       }
-    }
-    function toggleLayer(which) {
-      setLayer(which, !showsLayer(which));
-    }
-    function drawOsmItems(selection2) {
-      var osmKeys = ["osm", "notes"];
-      var osmLayers = layers.all().filter(function(obj) {
-        return osmKeys.indexOf(obj.id) !== -1;
-      });
-      var ul = selection2.selectAll(".layer-list-osm").data([0]);
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-osm").merge(ul);
-      var li = ul.selectAll(".list-item").data(osmLayers);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d) {
-        return "list-item list-item-" + d.id;
+      if (!showSplash) return;
+      corePreferences("sawSplash", true);
+      corePreferences("sawPrivacyVersion", context.privacyVersion);
+      _mainFileFetcher.get("intro_graph");
+      let modalSelection = uiModal(selection2);
+      modalSelection.select(".modal").attr("class", "modal-splash modal");
+      let introModal = modalSelection.select(".content").append("div").attr("class", "fillL");
+      introModal.append("div").attr("class", "modal-section").append("h3").call(_t.append("splash.welcome"));
+      let modalSection = introModal.append("div").attr("class", "modal-section");
+      modalSection.append("p").html(_t.html("splash.text", {
+        version: context.version,
+        website: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">' + _t.html("splash.changelog") + "</a>" },
+        github: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>' }
+      }));
+      modalSection.append("p").html(_t.html("splash.privacy", {
+        updateMessage,
+        privacyLink: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t("splash.privacy_policy") + "</a>" }
+      }));
+      uiSectionPrivacy(context).label(() => _t.append("splash.privacy_settings")).render(modalSection);
+      let buttonWrap = introModal.append("div").attr("class", "modal-actions");
+      let walkthrough = buttonWrap.append("button").attr("class", "walkthrough").on("click", () => {
+        context.container().call(uiIntro(context));
+        modalSelection.close();
       });
-      var labelEnter = liEnter.append("label").each(function(d) {
-        if (d.id === "osm") {
-          select_default2(this).call(
-            uiTooltip().title(() => _t.append("map_data.layers." + d.id + ".tooltip")).keys([uiCmd("\u2325" + _t("area_fill.wireframe.key"))]).placement("bottom")
-          );
-        } else {
-          select_default2(this).call(
-            uiTooltip().title(() => _t.append("map_data.layers." + d.id + ".tooltip")).placement("bottom")
-          );
+      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
+      walkthrough.append("div").call(_t.append("splash.walkthrough"));
+      let startEditing = buttonWrap.append("button").attr("class", "start-editing").on("click", modalSelection.close);
+      startEditing.append("svg").attr("class", "logo logo-features").append("use").attr("xlink:href", "#iD-logo-features");
+      startEditing.append("div").call(_t.append("splash.start"));
+      modalSelection.select("button.close").attr("class", "hide");
+    };
+  }
+
+  // modules/ui/status.js
+  function uiStatus(context) {
+    var osm = context.connection();
+    return function(selection2) {
+      if (!osm) return;
+      function update(err, apiStatus) {
+        selection2.html("");
+        if (err) {
+          if (apiStatus === "connectionSwitched") {
+            return;
+          } else if (apiStatus === "rateLimited") {
+            selection2.call(_t.append("osm_api_status.message.rateLimit")).append("a").attr("href", "#").attr("class", "api-status-login").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("login")).on("click.login", function(d3_event) {
+              d3_event.preventDefault();
+              osm.authenticate();
+            });
+          } else {
+            var throttledRetry = throttle_default(function() {
+              context.loadTiles(context.projection);
+              osm.reloadApiStatus();
+            }, 2e3);
+            selection2.call(_t.append("osm_api_status.message.error", { suffix: " " })).append("a").attr("href", "#").call(_t.append("osm_api_status.retry")).on("click.retry", function(d3_event) {
+              d3_event.preventDefault();
+              throttledRetry();
+            });
+          }
+        } else if (apiStatus === "readonly") {
+          selection2.call(_t.append("osm_api_status.message.readonly"));
+        } else if (apiStatus === "offline") {
+          selection2.call(_t.append("osm_api_status.message.offline"));
         }
+        selection2.attr("class", "api-status " + (err ? "error" : apiStatus));
+      }
+      osm.on("apiStatusChange.uiStatus", update);
+      context.history().on("storage_error", () => {
+        selection2.selectAll("span.local-storage-full").remove();
+        selection2.append("span").attr("class", "local-storage-full").call(_t.append("osm_api_status.message.local_storage_full"));
+        selection2.classed("error", true);
       });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d) {
-        toggleLayer(d.id);
-      });
-      labelEnter.append("span").html(function(d) {
-        return _t.html("map_data.layers." + d.id + ".title");
-      });
-      li.merge(liEnter).classed("active", function(d) {
-        return d.layer.enabled();
-      }).selectAll("input").property("checked", function(d) {
-        return d.layer.enabled();
-      });
+      window.setInterval(function() {
+        osm.reloadApiStatus();
+      }, 9e4);
+      osm.reloadApiStatus();
+    };
+  }
+
+  // modules/ui/tools/modes.js
+  function uiToolDrawModes(context) {
+    var tool = {
+      id: "old_modes",
+      label: _t.append("toolbar.add_feature")
+    };
+    var modes = [
+      modeAddPoint(context, {
+        title: _t.append("modes.add_point.title"),
+        button: "point",
+        description: _t.append("modes.add_point.description"),
+        preset: _mainPresetIndex.item("point"),
+        key: "1"
+      }),
+      modeAddLine(context, {
+        title: _t.append("modes.add_line.title"),
+        button: "line",
+        description: _t.append("modes.add_line.description"),
+        preset: _mainPresetIndex.item("line"),
+        key: "2"
+      }),
+      modeAddArea(context, {
+        title: _t.append("modes.add_area.title"),
+        button: "area",
+        description: _t.append("modes.add_area.description"),
+        preset: _mainPresetIndex.item("area"),
+        key: "3"
+      })
+    ];
+    function enabled(_mode) {
+      return osmEditable();
     }
-    function drawQAItems(selection2) {
-      var qaKeys = ["keepRight", "improveOSM", "osmose"];
-      var qaLayers = layers.all().filter(function(obj) {
-        return qaKeys.indexOf(obj.id) !== -1;
-      });
-      var ul = selection2.selectAll(".layer-list-qa").data([0]);
-      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-qa").merge(ul);
-      var li = ul.selectAll(".list-item").data(qaLayers);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d) {
-        return "list-item list-item-" + d.id;
-      });
-      var labelEnter = liEnter.append("label").each(function(d) {
-        select_default2(this).call(
-          uiTooltip().title(() => _t.append("map_data.layers." + d.id + ".tooltip")).placement("bottom")
-        );
-      });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d) {
-        toggleLayer(d.id);
-      });
-      labelEnter.append("span").each(function(d) {
-        _t.append("map_data.layers." + d.id + ".title")(select_default2(this));
-      });
-      li.merge(liEnter).classed("active", function(d) {
-        return d.layer.enabled();
-      }).selectAll("input").property("checked", function(d) {
-        return d.layer.enabled();
-      });
+    function osmEditable() {
+      return context.editable();
     }
-    function drawVectorItems(selection2) {
-      var dataLayer = layers.layer("data");
-      var vtData = [
-        {
-          name: "Detroit Neighborhoods/Parks",
-          src: "neighborhoods-parks",
-          tooltip: "Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.",
-          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmur6x34562qp9iv1u3ksf-54hev,jonahadkins.cjksmqxdx33jj2wp90xd9x2md-4e5y2/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
-        },
-        {
-          name: "Detroit Composite POIs",
-          src: "composite-poi",
-          tooltip: "Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.",
-          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmm6a02sli31myxhsr7zf3-2sw8h/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
-        },
-        {
-          name: "Detroit All-The-Places POIs",
-          src: "alltheplaces-poi",
-          tooltip: "Public domain business location data created by web scrapers.",
-          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmswgk340g2vo06p1w9w0j-8fjjc/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
+    modes.forEach(function(mode) {
+      context.keybinding().on(mode.key, function() {
+        if (!enabled(mode)) return;
+        if (mode.id === context.mode().id) {
+          context.enter(modeBrowse(context));
+        } else {
+          context.enter(mode);
         }
-      ];
-      var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
-      var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
-      var container = selection2.selectAll(".vectortile-container").data(showVectorItems ? [0] : []);
-      container.exit().remove();
-      var containerEnter = container.enter().append("div").attr("class", "vectortile-container");
-      containerEnter.append("h4").attr("class", "vectortile-header").text("Detroit Vector Tiles (Beta)");
-      containerEnter.append("ul").attr("class", "layer-list layer-list-vectortile");
-      containerEnter.append("div").attr("class", "vectortile-footer").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmus/detroit-mapping-challenge").append("span").text("About these layers");
-      container = container.merge(containerEnter);
-      var ul = container.selectAll(".layer-list-vectortile");
-      var li = ul.selectAll(".list-item").data(vtData);
-      li.exit().remove();
-      var liEnter = li.enter().append("li").attr("class", function(d) {
-        return "list-item list-item-" + d.src;
       });
-      var labelEnter = liEnter.append("label").each(function(d) {
-        select_default2(this).call(
-          uiTooltip().title(d.tooltip).placement("top")
+    });
+    tool.render = function(selection2) {
+      var wrap2 = selection2.append("div").attr("class", "joined").style("display", "flex");
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.map().on("move.modes", debouncedUpdate).on("drawn.modes", debouncedUpdate);
+      context.on("enter.modes", update);
+      update();
+      function update() {
+        var buttons = wrap2.selectAll("button.add-button").data(modes, function(d2) {
+          return d2.id;
+        });
+        buttons.exit().remove();
+        var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
+          return d2.id + " add-button bar-button";
+        }).on("click.mode-buttons", function(d3_event, d2) {
+          if (!enabled(d2)) return;
+          var currMode = context.mode().id;
+          if (/^draw/.test(currMode)) return;
+          if (d2.id === currMode) {
+            context.enter(modeBrowse(context));
+          } else {
+            context.enter(d2);
+          }
+        }).call(
+          uiTooltip().placement("bottom").title(function(d2) {
+            return d2.description;
+          }).keys(function(d2) {
+            return [d2.key];
+          }).scrollContainer(context.container().select(".top-toolbar"))
         );
-      });
-      labelEnter.append("input").attr("type", "radio").attr("name", "vectortile").on("change", selectVTLayer);
-      labelEnter.append("span").text(function(d) {
-        return d.name;
-      });
-      li.merge(liEnter).classed("active", isVTLayerSelected).selectAll("input").property("checked", isVTLayerSelected);
-      function isVTLayerSelected(d) {
-        return dataLayer && dataLayer.template() === d.template;
-      }
-      function selectVTLayer(d3_event, d) {
-        corePreferences("settings-custom-data-url", d.template);
-        if (dataLayer) {
-          dataLayer.template(d.template, d.src);
-          dataLayer.enabled(true);
+        buttonsEnter.each(function(d2) {
+          select_default2(this).call(svgIcon("#iD-icon-" + d2.button));
+        });
+        buttonsEnter.append("span").attr("class", "label").text("").each(function(mode) {
+          mode.title(select_default2(this));
+        });
+        if (buttons.enter().size() || buttons.exit().size()) {
+          context.ui().checkOverflow(".top-toolbar", true);
         }
+        buttons = buttons.merge(buttonsEnter).attr("aria-disabled", function(d2) {
+          return !enabled(d2);
+        }).classed("disabled", function(d2) {
+          return !enabled(d2);
+        }).attr("aria-pressed", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        }).classed("active", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        });
       }
+    };
+    return tool;
+  }
+
+  // modules/ui/tools/notes.js
+  function uiToolNotes(context) {
+    var tool = {
+      id: "notes",
+      label: _t.append("modes.add_note.label")
+    };
+    var mode = modeAddNote(context);
+    function enabled() {
+      return notesEnabled() && notesEditable();
     }
-    function drawCustomDataItems(selection2) {
-      var dataLayer = layers.layer("data");
-      var hasData = dataLayer && dataLayer.hasData();
-      var showsData = hasData && dataLayer.enabled();
-      var ul = selection2.selectAll(".layer-list-data").data(dataLayer ? [0] : []);
-      ul.exit().remove();
-      var ulEnter = ul.enter().append("ul").attr("class", "layer-list layer-list-data");
-      var liEnter = ulEnter.append("li").attr("class", "list-item-data");
-      var labelEnter = liEnter.append("label").call(
-        uiTooltip().title(() => _t.append("map_data.layers.custom.tooltip")).placement("top")
-      );
-      labelEnter.append("input").attr("type", "checkbox").on("change", function() {
-        toggleLayer("data");
-      });
-      labelEnter.append("span").call(_t.append("map_data.layers.custom.title"));
-      liEnter.append("button").attr("class", "open-data-options").call(
-        uiTooltip().title(() => _t.append("settings.custom_data.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        editCustom();
-      }).call(svgIcon("#iD-icon-more"));
-      liEnter.append("button").attr("class", "zoom-to-data").call(
-        uiTooltip().title(() => _t.append("map_data.layers.custom.zoom")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
-      ).on("click", function(d3_event) {
-        if (select_default2(this).classed("disabled"))
-          return;
-        d3_event.preventDefault();
-        d3_event.stopPropagation();
-        dataLayer.fitZoom();
-      }).call(svgIcon("#iD-icon-framed-dot", "monochrome"));
-      ul = ul.merge(ulEnter);
-      ul.selectAll(".list-item-data").classed("active", showsData).selectAll("label").classed("deemphasize", !hasData).selectAll("input").property("disabled", !hasData).property("checked", showsData);
-      ul.selectAll("button.zoom-to-data").classed("disabled", !hasData);
+    function notesEnabled() {
+      var noteLayer = context.layers().layer("notes");
+      return noteLayer && noteLayer.enabled();
     }
-    function editCustom() {
-      context.container().call(settingsCustomData);
+    function notesEditable() {
+      var mode2 = context.mode();
+      return context.map().notesEditable() && mode2 && mode2.id !== "save";
     }
-    function customChanged(d) {
-      var dataLayer = layers.layer("data");
-      if (d && d.url) {
-        dataLayer.url(d.url);
-      } else if (d && d.fileList) {
-        dataLayer.fileList(d.fileList);
+    context.keybinding().on(mode.key, function() {
+      if (!enabled()) return;
+      if (mode.id === context.mode().id) {
+        context.enter(modeBrowse(context));
+      } else {
+        context.enter(mode);
       }
-    }
-    function drawPanelItems(selection2) {
-      var panelsListEnter = selection2.selectAll(".md-extras-list").data([0]).enter().append("ul").attr("class", "layer-list md-extras-list");
-      var historyPanelLabelEnter = panelsListEnter.append("li").attr("class", "history-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("map_data.history_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.history.key"))]).placement("top")
-      );
-      historyPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("history");
-      });
-      historyPanelLabelEnter.append("span").call(_t.append("map_data.history_panel.title"));
-      var measurementPanelLabelEnter = panelsListEnter.append("li").attr("class", "measurement-panel-toggle-item").append("label").call(
-        uiTooltip().title(() => _t.append("map_data.measurement_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.measurement.key"))]).placement("top")
-      );
-      measurementPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
-        d3_event.preventDefault();
-        context.ui().info.toggle("measurement");
-      });
-      measurementPanelLabelEnter.append("span").call(_t.append("map_data.measurement_panel.title"));
-    }
-    context.layers().on("change.uiSectionDataLayers", section.reRender);
-    context.map().on(
-      "move.uiSectionDataLayers",
-      debounce_default(function() {
-        window.requestIdleCallback(section.reRender);
-      }, 1e3)
-    );
-    return section;
+    });
+    tool.render = function(selection2) {
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.map().on("move.notes", debouncedUpdate).on("drawn.notes", debouncedUpdate);
+      context.on("enter.notes", update);
+      update();
+      function update() {
+        var showNotes = notesEnabled();
+        var data = showNotes ? [mode] : [];
+        var buttons = selection2.selectAll("button.add-button").data(data, function(d2) {
+          return d2.id;
+        });
+        buttons.exit().remove();
+        var buttonsEnter = buttons.enter().append("button").attr("class", function(d2) {
+          return d2.id + " add-button bar-button";
+        }).on("click.notes", function(d3_event, d2) {
+          if (!enabled()) return;
+          var currMode = context.mode().id;
+          if (/^draw/.test(currMode)) return;
+          if (d2.id === currMode) {
+            context.enter(modeBrowse(context));
+          } else {
+            context.enter(d2);
+          }
+        }).call(
+          uiTooltip().placement("bottom").title(function(d2) {
+            return d2.description;
+          }).keys(function(d2) {
+            return [d2.key];
+          }).scrollContainer(context.container().select(".top-toolbar"))
+        );
+        buttonsEnter.each(function(d2) {
+          select_default2(this).call(svgIcon(d2.icon || "#iD-icon-" + d2.button));
+        });
+        if (buttons.enter().size() || buttons.exit().size()) {
+          context.ui().checkOverflow(".top-toolbar", true);
+        }
+        buttons = buttons.merge(buttonsEnter).classed("disabled", function() {
+          return !enabled();
+        }).attr("aria-disabled", function() {
+          return !enabled();
+        }).classed("active", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        }).attr("aria-pressed", function(d2) {
+          return context.mode() && context.mode().button === d2.button;
+        });
+      }
+    };
+    tool.uninstall = function() {
+      context.on("enter.editor.notes", null).on("exit.editor.notes", null).on("enter.notes", null);
+      context.map().on("move.notes", null).on("drawn.notes", null);
+    };
+    return tool;
   }
 
-  // modules/ui/sections/map_features.js
-  function uiSectionMapFeatures(context) {
-    var _features = context.features().keys();
-    var section = uiSection("map-features", context).label(() => _t.append("map_data.map_features")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-feature-list-container").data([0]);
-      var containerEnter = container.enter().append("div").attr("class", "layer-feature-list-container");
-      containerEnter.append("ul").attr("class", "layer-list layer-feature-list");
-      var footer = containerEnter.append("div").attr("class", "feature-list-links section-footer");
-      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.features().disableAll();
-      });
-      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
-        d3_event.preventDefault();
-        context.features().enableAll();
-      });
-      container = container.merge(containerEnter);
-      container.selectAll(".layer-feature-list").call(drawListItems, _features, "checkbox", "feature", clickFeature, showsFeature);
-    }
-    function drawListItems(selection2, data, type3, name, change, active) {
-      var items = selection2.selectAll("li").data(data);
-      items.exit().remove();
-      var enter = items.enter().append("li").call(
-        uiTooltip().title(function(d) {
-          var tip = _t.append(name + "." + d + ".tooltip");
-          if (autoHiddenFeature(d)) {
-            var msg = showsLayer("osm") ? _t.append("map_data.autohidden") : _t.append("map_data.osmhidden");
-            return (selection3) => {
-              selection3.call(tip);
-              selection3.append("div").call(msg);
-            };
-          }
-          return tip;
-        }).placement("top")
-      );
-      var label = enter.append("label");
-      label.append("input").attr("type", type3).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", autoHiddenFeature);
+  // modules/ui/tools/save.js
+  function uiToolSave(context) {
+    var tool = {
+      id: "save",
+      label: _t.append("save.title")
+    };
+    var button = null;
+    var tooltipBehavior = null;
+    var history = context.history();
+    var key = uiCmd("\u2318S");
+    var _numChanges = 0;
+    function isSaving() {
+      var mode = context.mode();
+      return mode && mode.id === "save";
     }
-    function autoHiddenFeature(d) {
-      return context.features().autoHidden(d);
+    function isDisabled() {
+      return _numChanges === 0 || isSaving();
     }
-    function showsFeature(d) {
-      return context.features().enabled(d);
+    function save(d3_event) {
+      d3_event.preventDefault();
+      if (!context.inIntro() && !isSaving() && history.hasChanges()) {
+        context.enter(modeSave(context));
+      }
     }
-    function clickFeature(d3_event, d) {
-      context.features().toggle(d);
+    function bgColor(numChanges) {
+      var step;
+      if (numChanges === 0) {
+        return null;
+      } else if (numChanges <= 50) {
+        step = numChanges / 50;
+        return rgb_default("#fff", "#ff8")(step);
+      } else {
+        step = Math.min((numChanges - 50) / 50, 1);
+        return rgb_default("#ff8", "#f88")(step);
+      }
     }
-    function showsLayer(id2) {
-      var layer = context.layers().layer(id2);
-      return layer && layer.enabled();
+    function updateCount() {
+      var val = history.difference().summary().length;
+      if (val === _numChanges) return;
+      _numChanges = val;
+      if (tooltipBehavior) {
+        tooltipBehavior.title(() => _t.append(_numChanges > 0 ? "save.help" : "save.no_changes")).keys([key]);
+      }
+      if (button) {
+        button.classed("disabled", isDisabled()).style("background", bgColor(_numChanges));
+        button.select("span.count").text(_numChanges);
+      }
     }
-    context.features().on("change.map_features", section.reRender);
-    return section;
+    tool.render = function(selection2) {
+      tooltipBehavior = uiTooltip().placement("bottom").title(() => _t.append("save.no_changes")).keys([key]).scrollContainer(context.container().select(".top-toolbar"));
+      var lastPointerUpType;
+      button = selection2.append("button").attr("class", "save disabled bar-button").on("pointerup", function(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
+      }).on("click", function(d3_event) {
+        save(d3_event);
+        if (_numChanges === 0 && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
+          context.ui().flash.duration(2e3).iconName("#iD-icon-save").iconClass("disabled").label(_t.append("save.no_changes"))();
+        }
+        lastPointerUpType = null;
+      }).call(tooltipBehavior);
+      button.call(svgIcon("#iD-icon-save"));
+      button.append("span").attr("class", "count").attr("aria-hidden", "true").text("0");
+      updateCount();
+      context.keybinding().on(key, save, true);
+      context.history().on("change.save", updateCount);
+      context.on("enter.save", function() {
+        if (button) {
+          button.classed("disabled", isDisabled());
+          if (isSaving()) {
+            button.call(tooltipBehavior.hide);
+          }
+        }
+      });
+    };
+    tool.uninstall = function() {
+      context.keybinding().off(key, true);
+      context.history().on("change.save", null);
+      context.on("enter.save", null);
+      button = null;
+      tooltipBehavior = null;
+    };
+    return tool;
   }
 
-  // modules/ui/sections/map_style_options.js
-  function uiSectionMapStyleOptions(context) {
-    var section = uiSection("fill-area", context).label(() => _t.append("map_data.style_options")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
-    function renderDisclosureContent(selection2) {
-      var container = selection2.selectAll(".layer-fill-list").data([0]);
-      container.enter().append("ul").attr("class", "layer-list layer-fill-list").merge(container).call(drawListItems, context.map().areaFillOptions, "radio", "area_fill", setFill, isActiveFill);
-      var container2 = selection2.selectAll(".layer-visual-diff-list").data([0]);
-      container2.enter().append("ul").attr("class", "layer-list layer-visual-diff-list").merge(container2).call(drawListItems, ["highlight_edits"], "checkbox", "visual_diff", toggleHighlightEdited, function() {
-        return context.surface().classed("highlight-edited");
+  // modules/ui/tools/sidebar_toggle.js
+  function uiToolSidebarToggle(context) {
+    var tool = {
+      id: "sidebar_toggle",
+      label: _t.append("toolbar.inspect")
+    };
+    tool.render = function(selection2) {
+      selection2.append("button").attr("class", "bar-button").attr("aria-label", _t("sidebar.tooltip")).on("click", function() {
+        context.ui().sidebar.toggle();
+      }).call(
+        uiTooltip().placement("bottom").title(() => _t.append("sidebar.tooltip")).keys([_t("sidebar.key")]).scrollContainer(context.container().select(".top-toolbar"))
+      ).call(svgIcon("#iD-icon-sidebar-" + (_mainLocalizer.textDirection() === "rtl" ? "right" : "left")));
+    };
+    return tool;
+  }
+
+  // modules/ui/tools/undo_redo.js
+  function uiToolUndoRedo(context) {
+    var tool = {
+      id: "undo_redo",
+      label: _t.append("toolbar.undo_redo")
+    };
+    var commands = [{
+      id: "undo",
+      cmd: uiCmd("\u2318Z"),
+      action: function() {
+        context.undo();
+      },
+      annotation: function() {
+        return context.history().undoAnnotation();
+      },
+      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")
+    }, {
+      id: "redo",
+      cmd: uiCmd("\u2318\u21E7Z"),
+      action: function() {
+        context.redo();
+      },
+      annotation: function() {
+        return context.history().redoAnnotation();
+      },
+      icon: "iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "undo" : "redo")
+    }];
+    function editable() {
+      return context.mode() && context.mode().id !== "save" && context.map().editableDataEnabled(
+        true
+        /* ignore min zoom */
+      );
+    }
+    tool.render = function(selection2) {
+      var tooltipBehavior = uiTooltip().placement("bottom").title(function(d2) {
+        return d2.annotation() ? _t.append(d2.id + ".tooltip", { action: d2.annotation() }) : _t.append(d2.id + ".nothing");
+      }).keys(function(d2) {
+        return [d2.cmd];
+      }).scrollContainer(context.container().select(".top-toolbar"));
+      var lastPointerUpType;
+      var buttons = selection2.selectAll("button").data(commands).enter().append("button").attr("class", function(d2) {
+        return "disabled " + d2.id + "-button bar-button";
+      }).on("pointerup", function(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        var annotation = d2.annotation();
+        if (editable() && annotation) {
+          d2.action();
+        }
+        if (editable() && (lastPointerUpType === "touch" || lastPointerUpType === "pen")) {
+          var label = annotation ? _t.append(d2.id + ".tooltip", { action: annotation }) : _t.append(d2.id + ".nothing");
+          context.ui().flash.duration(2e3).iconName("#" + d2.icon).iconClass(annotation ? "" : "disabled").label(label)();
+        }
+        lastPointerUpType = null;
+      }).call(tooltipBehavior);
+      buttons.each(function(d2) {
+        select_default2(this).call(svgIcon("#" + d2.icon));
+      });
+      context.keybinding().on(commands[0].cmd, function(d3_event) {
+        d3_event.preventDefault();
+        if (editable()) commands[0].action();
+      }).on(commands[1].cmd, function(d3_event) {
+        d3_event.preventDefault();
+        if (editable()) commands[1].action();
+      });
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.map().on("move.undo_redo", debouncedUpdate).on("drawn.undo_redo", debouncedUpdate);
+      context.history().on("change.undo_redo", function(difference2) {
+        if (difference2) update();
       });
+      context.on("enter.undo_redo", update);
+      function update() {
+        buttons.classed("disabled", function(d2) {
+          return !editable() || !d2.annotation();
+        }).each(function() {
+          var selection3 = select_default2(this);
+          if (!selection3.select(".tooltip.in").empty()) {
+            selection3.call(tooltipBehavior.updateContent);
+          }
+        });
+      }
+    };
+    tool.uninstall = function() {
+      context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
+      context.map().on("move.undo_redo", null).on("drawn.undo_redo", null);
+      context.history().on("change.undo_redo", null);
+      context.on("enter.undo_redo", null);
+    };
+    return tool;
+  }
+
+  // modules/ui/top_toolbar.js
+  function uiTopToolbar(context) {
+    var sidebarToggle = uiToolSidebarToggle(context), modes = uiToolDrawModes(context), notes = uiToolNotes(context), undoRedo = uiToolUndoRedo(context), save = uiToolSave(context);
+    function notesEnabled() {
+      var noteLayer = context.layers().layer("notes");
+      return noteLayer && noteLayer.enabled();
     }
-    function drawListItems(selection2, data, type3, name, change, active) {
-      var items = selection2.selectAll("li").data(data);
-      items.exit().remove();
-      var enter = items.enter().append("li").call(
-        uiTooltip().title(function(d) {
-          return _t.append(name + "." + d + ".tooltip");
-        }).keys(function(d) {
-          var key = d === "wireframe" ? _t("area_fill.wireframe.key") : null;
-          if (d === "highlight_edits")
-            key = _t("map_data.highlight_edits.key");
-          return key ? [key] : null;
-        }).placement("top")
-      );
-      var label = enter.append("label");
-      label.append("input").attr("type", type3).attr("name", name).on("change", change);
-      label.append("span").html(function(d) {
-        return _t.html(name + "." + d + ".description");
+    function topToolbar(bar) {
+      bar.on("wheel.topToolbar", function(d3_event) {
+        if (!d3_event.deltaX) {
+          bar.node().scrollLeft += d3_event.deltaY;
+        }
       });
-      items = items.merge(enter);
-      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
+      var debouncedUpdate = debounce_default(update, 500, { leading: true, trailing: true });
+      context.layers().on("change.topToolbar", debouncedUpdate);
+      update();
+      function update() {
+        var tools = [
+          sidebarToggle,
+          "spacer",
+          modes
+        ];
+        tools.push("spacer");
+        if (notesEnabled()) {
+          tools = tools.concat([notes, "spacer"]);
+        }
+        tools = tools.concat([undoRedo, save]);
+        var toolbarItems = bar.selectAll(".toolbar-item").data(tools, function(d2) {
+          return d2.id || d2;
+        });
+        toolbarItems.exit().each(function(d2) {
+          if (d2.uninstall) {
+            d2.uninstall();
+          }
+        }).remove();
+        var itemsEnter = toolbarItems.enter().append("div").attr("class", function(d2) {
+          var classes = "toolbar-item " + (d2.id || d2).replace("_", "-");
+          if (d2.klass) classes += " " + d2.klass;
+          return classes;
+        });
+        var actionableItems = itemsEnter.filter(function(d2) {
+          return d2 !== "spacer";
+        });
+        actionableItems.append("div").attr("class", "item-content").each(function(d2) {
+          select_default2(this).call(d2.render, bar);
+        });
+        actionableItems.append("div").attr("class", "item-label").each(function(d2) {
+          d2.label(select_default2(this));
+        });
+      }
     }
-    function isActiveFill(d) {
-      return context.map().activeAreaFill() === d;
+    return topToolbar;
+  }
+
+  // modules/ui/version.js
+  var sawVersion = null;
+  var isNewVersion = false;
+  var isNewUser = false;
+  function uiVersion(context) {
+    var currVersion = context.version;
+    var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
+    if (sawVersion === null && matchedVersion !== null) {
+      if (corePreferences("sawVersion")) {
+        isNewUser = false;
+        isNewVersion = corePreferences("sawVersion") !== currVersion && currVersion.indexOf("-") === -1;
+      } else {
+        isNewUser = true;
+        isNewVersion = true;
+      }
+      corePreferences("sawVersion", currVersion);
+      sawVersion = currVersion;
     }
-    function toggleHighlightEdited(d3_event) {
+    return function(selection2) {
+      selection2.append("a").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD").text(currVersion);
+      if (isNewVersion && !isNewUser) {
+        selection2.append("a").attr("class", "badge").attr("target", "_blank").attr("href", "https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new").call(svgIcon("#maki-gift")).call(
+          uiTooltip().title(() => _t.append("version.whats_new", { version: currVersion })).placement("top").scrollContainer(context.container().select(".main-footer-wrap"))
+        );
+      }
+    };
+  }
+
+  // modules/ui/zoom.js
+  function uiZoom(context) {
+    var zooms = [{
+      id: "zoom-in",
+      icon: "iD-icon-plus",
+      title: _t.append("zoom.in"),
+      action: zoomIn,
+      disabled: function() {
+        return !context.map().canZoomIn();
+      },
+      disabledTitle: _t.append("zoom.disabled.in"),
+      key: "+"
+    }, {
+      id: "zoom-out",
+      icon: "iD-icon-minus",
+      title: _t.append("zoom.out"),
+      action: zoomOut,
+      disabled: function() {
+        return !context.map().canZoomOut();
+      },
+      disabledTitle: _t.append("zoom.disabled.out"),
+      key: "-"
+    }];
+    function zoomIn(d3_event) {
+      if (d3_event.shiftKey) return;
       d3_event.preventDefault();
-      context.map().toggleHighlightEdited();
+      context.map().zoomIn();
     }
-    function setFill(d3_event, d) {
-      context.map().activeAreaFill(d);
+    function zoomOut(d3_event) {
+      if (d3_event.shiftKey) return;
+      d3_event.preventDefault();
+      context.map().zoomOut();
     }
-    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 zoomInFurther(d3_event) {
+      if (d3_event.shiftKey) return;
+      d3_event.preventDefault();
+      context.map().zoomInFurther();
     }
-    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";
+    function zoomOutFurther(d3_event) {
+      if (d3_event.shiftKey) return;
+      d3_event.preventDefault();
+      context.map().zoomOutFurther();
+    }
+    return function(selection2) {
+      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function(d2) {
+        if (d2.disabled()) {
+          return d2.disabledTitle;
         }
-        return classes;
+        return d2.title;
+      }).keys(function(d2) {
+        return [d2.key];
       });
-      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")
-        );
+      var lastPointerUpType;
+      var buttons = selection2.selectAll("button").data(zooms).enter().append("button").attr("class", function(d2) {
+        return d2.id;
+      }).on("pointerup.editor", function(d3_event) {
+        lastPointerUpType = d3_event.pointerType;
+      }).on("click.editor", function(d3_event, d2) {
+        if (!d2.disabled()) {
+          d2.action(d3_event);
+        } else if (lastPointerUpType === "touch" || lastPointerUpType === "pen") {
+          context.ui().flash.duration(2e3).iconName("#" + d2.icon).iconClass("disabled").label(d2.disabledTitle)();
+        }
+        lastPointerUpType = null;
+      }).call(tooltipBehavior);
+      buttons.each(function(d2) {
+        select_default2(this).call(svgIcon("#" + d2.icon, "light"));
       });
-      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d) {
-        toggleLayer(d.id);
+      utilKeybinding.plusKeys.forEach(function(key) {
+        context.keybinding().on([key], zoomIn);
+        context.keybinding().on([uiCmd("\u2325" + key)], zoomInFurther);
       });
-      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");
+      utilKeybinding.minusKeys.forEach(function(key) {
+        context.keybinding().on([key], zoomOut);
+        context.keybinding().on([uiCmd("\u2325" + key)], zoomOutFurther);
       });
-      li.merge(liEnter).classed("active", layerEnabled).selectAll("input").property("checked", layerEnabled);
+      function updateButtonStates() {
+        buttons.classed("disabled", function(d2) {
+          return d2.disabled();
+        }).each(function() {
+          var selection3 = select_default2(this);
+          if (!selection3.select(".tooltip.in").empty()) {
+            selection3.call(tooltipBehavior.updateContent);
+          }
+        });
+      }
+      updateButtonStates();
+      context.map().on("move.uiZoom", updateButtonStates);
+    };
+  }
+
+  // modules/ui/zoom_to_selection.js
+  function uiZoomToSelection(context) {
+    function isDisabled() {
+      var mode = context.mode();
+      return !mode || !mode.zoomToSelected;
     }
-    function drawPhotoTypeItems(selection2) {
-      var data = context.photos().allPhotoTypes();
-      function typeEnabled(d) {
-        return context.photos().showsPhotoType(d);
+    var _lastPointerUpType;
+    function pointerup(d3_event) {
+      _lastPointerUpType = d3_event.pointerType;
+    }
+    function click(d3_event) {
+      d3_event.preventDefault();
+      if (isDisabled()) {
+        if (_lastPointerUpType === "touch" || _lastPointerUpType === "pen") {
+          context.ui().flash.duration(2e3).iconName("#iD-icon-framed-dot").iconClass("disabled").label(_t.append("inspector.zoom_to.no_selection"))();
+        }
+      } else {
+        var mode = context.mode();
+        if (mode && mode.zoomToSelected) {
+          mode.zoomToSelected();
+        }
       }
-      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);
+      _lastPointerUpType = null;
     }
-    function drawDateFilter(selection2) {
-      var data = context.photos().dateFilters();
-      function filterEnabled(d) {
-        return context.photos().dateFilterValue(d);
+    return function(selection2) {
+      var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(function() {
+        if (isDisabled()) {
+          return _t.append("inspector.zoom_to.no_selection");
+        }
+        return _t.append("inspector.zoom_to.title");
+      }).keys([_t("inspector.zoom_to.key")]);
+      var button = selection2.append("button").on("pointerup", pointerup).on("click", click).call(svgIcon("#iD-icon-framed-dot", "light")).call(tooltipBehavior);
+      function setEnabledState() {
+        button.classed("disabled", isDisabled());
+        if (!button.select(".tooltip.in").empty()) {
+          button.call(tooltipBehavior.updateContent);
+        }
       }
-      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);
+      context.on("enter.uiZoomToSelection", setEnabledState);
+      setEnabledState();
+    };
+  }
+
+  // modules/ui/pane.js
+  function uiPane(id2, context) {
+    var _key;
+    var _label = "";
+    var _description = "";
+    var _iconName = "";
+    var _sections;
+    var _paneSelection = select_default2(null);
+    var _paneTooltip;
+    var pane = {
+      id: id2
+    };
+    pane.label = function(val) {
+      if (!arguments.length) return _label;
+      _label = val;
+      return pane;
+    };
+    pane.key = function(val) {
+      if (!arguments.length) return _key;
+      _key = val;
+      return pane;
+    };
+    pane.description = function(val) {
+      if (!arguments.length) return _description;
+      _description = val;
+      return pane;
+    };
+    pane.iconName = function(val) {
+      if (!arguments.length) return _iconName;
+      _iconName = val;
+      return pane;
+    };
+    pane.sections = function(val) {
+      if (!arguments.length) return _sections;
+      _sections = val;
+      return pane;
+    };
+    pane.selection = function() {
+      return _paneSelection;
+    };
+    function hidePane() {
+      context.ui().togglePanes();
     }
-    function drawUsernameFilter(selection2) {
-      function filterEnabled() {
-        return context.photos().usernames();
+    pane.togglePane = function(d3_event) {
+      if (d3_event) d3_event.preventDefault();
+      _paneTooltip.hide();
+      context.ui().togglePanes(!_paneSelection.classed("shown") ? _paneSelection : void 0);
+    };
+    pane.renderToggleButton = function(selection2) {
+      if (!_paneTooltip) {
+        _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left").title(() => _description).keys([_key]);
       }
-      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;
+      selection2.append("button").on("click", pane.togglePane).call(svgIcon("#" + _iconName, "light")).call(_paneTooltip);
+    };
+    pane.renderContent = function(selection2) {
+      if (_sections) {
+        _sections.forEach(function(section) {
+          selection2.call(section.render);
+        });
       }
+    };
+    pane.renderPane = function(selection2) {
+      _paneSelection = selection2.append("div").attr("class", "fillL map-pane hide " + id2 + "-pane").attr("pane", id2);
+      var heading2 = _paneSelection.append("div").attr("class", "pane-heading");
+      heading2.append("h2").text("").call(_label);
+      heading2.append("button").attr("title", _t("icons.close")).on("click", hidePane).call(svgIcon("#iD-icon-close"));
+      _paneSelection.append("div").attr("class", "pane-content").call(pane.renderContent);
+      if (_key) {
+        context.keybinding().on(_key, pane.togglePane);
+      }
+    };
+    return pane;
+  }
+
+  // modules/ui/sections/background_display_options.js
+  function uiSectionBackgroundDisplayOptions(context) {
+    var section = uiSection("background-display-options", context).label(() => _t.append("background.display_options")).disclosureContent(renderDisclosureContent);
+    var _storedOpacity = corePreferences("background-opacity");
+    var _minVal = 0;
+    var _maxVal = 3;
+    var _sliders = ["brightness", "contrast", "saturation", "sharpness"];
+    var _options = {
+      brightness: _storedOpacity !== null ? +_storedOpacity : 1,
+      contrast: 1,
+      saturation: 1,
+      sharpness: 1
+    };
+    function clamp3(x2, min3, max3) {
+      return Math.max(min3, Math.min(x2, max3));
     }
-    function toggleLayer(which) {
-      setLayer(which, !showsLayer(which));
-    }
-    function showsLayer(which) {
-      var layer = layers.layer(which);
-      if (layer) {
-        return layer.enabled();
+    function updateValue(d2, val) {
+      val = clamp3(val, _minVal, _maxVal);
+      _options[d2] = val;
+      context.background()[d2](val);
+      if (d2 === "brightness") {
+        corePreferences("background-opacity", val);
       }
-      return false;
+      section.reRender();
     }
-    function setLayer(which, enabled) {
-      var layer = layers.layer(which);
-      if (layer) {
-        layer.enabled(enabled);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".display-options-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "display-options-container controls-list");
+      var slidersEnter = containerEnter.selectAll(".display-control").data(_sliders).enter().append("label").attr("class", function(d2) {
+        return "display-control display-control-" + d2;
+      });
+      slidersEnter.html(function(d2) {
+        return _t.html("background." + d2);
+      }).append("span").attr("class", function(d2) {
+        return "display-option-value display-option-value-" + d2;
+      });
+      var sildersControlEnter = slidersEnter.append("div").attr("class", "control-wrap");
+      sildersControlEnter.append("input").attr("class", function(d2) {
+        return "display-option-input display-option-input-" + d2;
+      }).attr("type", "range").attr("min", _minVal).attr("max", _maxVal).attr("step", "0.05").on("input", function(d3_event, d2) {
+        var val = select_default2(this).property("value");
+        if (!val && d3_event && d3_event.target) {
+          val = d3_event.target.value;
+        }
+        updateValue(d2, val);
+      });
+      sildersControlEnter.append("button").attr("title", function(d2) {
+        return "".concat(_t("background.reset"), " ").concat(_t("background." + d2));
+      }).attr("class", function(d2) {
+        return "display-option-reset display-option-reset-" + d2;
+      }).on("click", function(d3_event, d2) {
+        if (d3_event.button !== 0) return;
+        updateValue(d2, 1);
+      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
+      containerEnter.append("a").attr("class", "display-option-resetlink").attr("role", "button").attr("href", "#").call(_t.append("background.reset_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        for (var i3 = 0; i3 < _sliders.length; i3++) {
+          updateValue(_sliders[i3], 1);
+        }
+      });
+      container = containerEnter.merge(container);
+      container.selectAll(".display-option-input").property("value", function(d2) {
+        return _options[d2];
+      });
+      container.selectAll(".display-option-value").text(function(d2) {
+        return Math.floor(_options[d2] * 100) + "%";
+      });
+      container.selectAll(".display-option-reset").classed("disabled", function(d2) {
+        return _options[d2] === 1;
+      });
+      if (containerEnter.size() && _options.brightness !== 1) {
+        context.background().brightness(_options.brightness);
       }
     }
-    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/settings/custom_background.js
+  function uiSettingsCustomBackground() {
+    var dispatch14 = dispatch_default("change");
+    function render(selection2) {
+      var _origSettings = {
+        template: corePreferences("background-custom-template")
+      };
+      var _currSettings = {
+        template: corePreferences("background-custom-template")
+      };
+      var example = "https://tile.openstreetmap.org/{zoom}/{x}/{y}.png";
+      var modal = uiConfirm(selection2).okButton();
+      modal.classed("settings-modal settings-custom-background", true);
+      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_background.header"));
+      var textSection = modal.select(".modal-section.message-text");
+      var instructions = "".concat(_t.html("settings.custom_background.instructions.info"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.wms.tokens_label"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.proj"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.wkid"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.dimensions"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.wms.tokens.bbox"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.tms.tokens_label"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.xyz"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.flipped_y"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.switch"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.quadtile"), "\n") + "* ".concat(_t.html("settings.custom_background.instructions.tms.tokens.scale_factor"), "\n") + "\n" + "#### ".concat(_t.html("settings.custom_background.instructions.example"), "\n") + "`".concat(example, "`");
+      textSection.append("div").attr("class", "instructions-template").html(marked(instructions));
+      textSection.append("textarea").attr("class", "field-template").attr("placeholder", _t("settings.custom_background.template.placeholder")).call(utilNoAuto).property("value", _currSettings.template);
+      var buttonSection = modal.select(".modal-section.buttons");
+      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
+      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
+      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
+      function isSaveDisabled() {
+        return null;
+      }
+      function clickCancel() {
+        textSection.select(".field-template").property("value", _origSettings.template);
+        corePreferences("background-custom-template", _origSettings.template);
+        this.blur();
+        modal.close();
+      }
+      function clickSave() {
+        _currSettings.template = textSection.select(".field-template").property("value");
+        corePreferences("background-custom-template", _currSettings.template);
+        this.blur();
+        modal.close();
+        dispatch14.call("change", this, _currSettings);
+      }
+    }
+    return utilRebind(render, dispatch14, "on");
   }
 
-  // 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 && (node.nodeName === "INPUT" || node.nodeName === "LABEL" || node.nodeName === "A");
-        });
-        if (isOkayTarget)
-          return;
+  // modules/ui/sections/background_list.js
+  function uiSectionBackgroundList(context) {
+    var _backgroundList = select_default2(null);
+    var _customSource = context.background().findSource("custom");
+    var _settingsCustomBackground = uiSettingsCustomBackground(context).on("change", customChanged);
+    var section = uiSection("background-list", context).label(() => _t.append("background.backgrounds")).disclosureContent(renderDisclosureContent);
+    function previousBackgroundID() {
+      return corePreferences("background-last-used-toggle");
+    }
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".layer-background-list").data([0]);
+      _backgroundList = container.enter().append("ul").attr("class", "layer-list layer-background-list").attr("dir", "auto").merge(container);
+      var bgExtrasListEnter = selection2.selectAll(".bg-extras-list").data([0]).enter().append("ul").attr("class", "layer-list bg-extras-list");
+      var minimapLabelEnter = bgExtrasListEnter.append("li").attr("class", "minimap-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("background.minimap.tooltip")).keys([_t("background.minimap.key")]).placement("top")
+      );
+      minimapLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
         d3_event.preventDefault();
+        uiMapInMap.toggle();
       });
-      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"))();
+      minimapLabelEnter.append("span").call(_t.append("background.minimap.description"));
+      var panelLabelEnter = bgExtrasListEnter.append("li").attr("class", "background-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("background.panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.background.key"))]).placement("top")
+      );
+      panelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("background");
       });
-      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;
+      panelLabelEnter.append("span").call(_t.append("background.panel.description"));
+      var locPanelLabelEnter = bgExtrasListEnter.append("li").attr("class", "location-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("background.location_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.location.key"))]).placement("top")
+      );
+      locPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("location");
+      });
+      locPanelLabelEnter.append("span").call(_t.append("background.location_panel.description"));
+      selection2.selectAll(".imagery-faq").data([0]).enter().append("div").attr("class", "imagery-faq").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/openstreetmap/iD/blob/develop/FAQ.md#how-can-i-report-an-issue-with-background-imagery").append("span").call(_t.append("background.imagery_problem_faq"));
+      _backgroundList.call(drawListItems, "radio", function(d3_event, d2) {
+        chooseBackground(d2);
+      }, function(d2) {
+        return !d2.isHidden() && !d2.overlay;
+      });
+    }
+    function setTooltips(selection2) {
+      selection2.each(function(d2, i3, nodes) {
+        var item = select_default2(this).select("label");
+        var span = item.select("span");
+        var placement = i3 < nodes.length / 2 ? "bottom" : "top";
+        var hasDescription = d2.hasDescription();
+        var isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
+        item.call(uiTooltip().destroyAny);
+        if (d2.id === previousBackgroundID()) {
+          item.call(
+            uiTooltip().placement(placement).title(() => _t.append("background.switch")).keys([uiCmd("\u2318" + _t("background.key"))])
+          );
+        } else if (hasDescription || isOverflowing) {
+          item.call(
+            uiTooltip().placement(placement).title(() => hasDescription ? d2.description() : d2.label())
+          );
         }
       });
-      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);
+    }
+    function drawListItems(layerList, type2, change, filter2) {
+      var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter2).sort(function(a2, b2) {
+        return a2.best() && !b2.best() ? -1 : b2.best() && !a2.best() ? 1 : descending(a2.area(), b2.area()) || ascending(a2.name(), b2.name()) || 0;
       });
-      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 layerLinks = layerList.selectAll("li").data(sources, function(d2, i3) {
+        return d2.id + "---" + i3;
       });
-      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();
+      layerLinks.exit().remove();
+      var enter = layerLinks.enter().append("li").classed("layer-custom", function(d2) {
+        return d2.id === "custom";
+      }).classed("best", function(d2) {
+        return d2.best();
       });
-      context.on("enter.editor", function(entered) {
-        container.classed("mode-" + entered.id, true);
-      }).on("exit.editor", function(exited) {
-        container.classed("mode-" + exited.id, false);
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", "background-layer").attr("value", function(d2) {
+        return d2.id;
+      }).on("change", change);
+      label.append("span").each(function(d2) {
+        d2.label()(select_default2(this));
       });
-      context.enter(modeBrowse(context));
-      if (!_initCounter++) {
-        if (!ui.hash.startWalkthrough) {
-          context.container().call(uiSplash(context)).call(uiRestore(context));
-        }
-        context.container().call(ui.shortcuts);
+      enter.filter(function(d2) {
+        return d2.id === "custom";
+      }).append("button").attr("class", "layer-browse").call(
+        uiTooltip().title(() => _t.append("settings.custom_background.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        editCustom();
+      }).call(svgIcon("#iD-icon-more"));
+      enter.filter(function(d2) {
+        return d2.best();
+      }).append("div").attr("class", "best").call(
+        uiTooltip().title(() => _t.append("background.best_imagery")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).append("span").text("\u2605");
+      layerList.call(updateLayerSelections);
+    }
+    function updateLayerSelections(selection2) {
+      function active(d2) {
+        return context.background().showsLayer(d2);
       }
-      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();
-        });
+      selection2.selectAll("li").classed("active", active).classed("switch", function(d2) {
+        return d2.id === previousBackgroundID();
+      }).call(setTooltips).selectAll("input").property("checked", active);
+    }
+    function chooseBackground(d2) {
+      if (d2.id === "custom" && !d2.template()) {
+        return editCustom();
       }
-      _initCounter++;
-      if (ui.hash.startWalkthrough) {
-        ui.hash.startWalkthrough = false;
-        context.container().call(uiIntro(context));
+      var previousBackground = context.background().baseLayerSource();
+      corePreferences("background-last-used-toggle", previousBackground.id);
+      corePreferences("background-last-used", d2.id);
+      context.background().baseLayerSource(d2);
+    }
+    function customChanged(d2) {
+      if (d2 && d2.template) {
+        _customSource.template(d2.template);
+        chooseBackground(_customSource);
+      } else {
+        _customSource.template("");
+        chooseBackground(context.background().findSource("none"));
       }
-      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);
-        };
+    }
+    function editCustom() {
+      context.container().call(_settingsCustomBackground);
+    }
+    context.background().on("change.background_list", function() {
+      _backgroundList.call(updateLayerSelections);
+    });
+    context.map().on(
+      "move.background_list",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
+  }
+
+  // modules/ui/sections/background_offset.js
+  function uiSectionBackgroundOffset(context) {
+    var section = uiSection("background-offset", context).label(() => _t.append("background.fix_misalignment")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
+    var _pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
+    var _directions = [
+      ["top", [0, -0.5]],
+      ["left", [-0.5, 0]],
+      ["right", [0.5, 0]],
+      ["bottom", [0, 0.5]]
+    ];
+    function updateValue() {
+      var meters = geoOffsetToMeters(context.background().offset());
+      var x2 = +meters[0].toFixed(2);
+      var y2 = +meters[1].toFixed(2);
+      context.container().selectAll(".nudge-inner-rect").select("input").classed("error", false).property("value", x2 + ", " + y2);
+      context.container().selectAll(".nudge-reset").classed("disabled", function() {
+        return x2 === 0 && y2 === 0;
+      });
+    }
+    function resetOffset() {
+      context.background().offset([0, 0]);
+      updateValue();
+    }
+    function nudge(d2) {
+      context.background().nudge(d2, context.map().zoom());
+      updateValue();
+    }
+    function inputOffset() {
+      var input = select_default2(this);
+      var d2 = input.node().value;
+      if (d2 === "") return resetOffset();
+      d2 = d2.replace(/;/g, ",").split(",").map(function(n3) {
+        return !isNaN(n3) && n3;
+      });
+      if (d2.length !== 2 || !d2[0] || !d2[1]) {
+        input.classed("error", true);
+        return;
       }
+      context.background().offset(geoMetersToOffset(d2));
+      updateValue();
     }
-    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);
+    function dragOffset(d3_event) {
+      if (d3_event.button !== 0) return;
+      var origin = [d3_event.clientX, d3_event.clientY];
+      var pointerId = d3_event.pointerId || "mouse";
+      context.container().append("div").attr("class", "nudge-surface");
+      select_default2(window).on(_pointerPrefix + "move.drag-bg-offset", pointermove).on(_pointerPrefix + "up.drag-bg-offset", pointerup);
+      if (_pointerPrefix === "pointer") {
+        select_default2(window).on("pointercancel.drag-bg-offset", pointerup);
       }
-      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];
+      function pointermove(d3_event2) {
+        if (pointerId !== (d3_event2.pointerId || "mouse")) return;
+        var latest = [d3_event2.clientX, d3_event2.clientY];
+        var d2 = [
+          -(origin[0] - latest[0]) / 4,
+          -(origin[1] - latest[1]) / 4
+        ];
+        origin = latest;
+        nudge(d2);
       }
-      var 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);
+      function pointerup(d3_event2) {
+        if (pointerId !== (d3_event2.pointerId || "mouse")) return;
+        if (d3_event2.button !== 0) return;
+        context.container().selectAll(".nudge-surface").remove();
+        select_default2(window).on(".drag-bg-offset", null);
       }
-    };
-    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");
+    }
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".nudge-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "nudge-container");
+      containerEnter.append("div").attr("class", "nudge-instructions").call(_t.append("background.offset"));
+      var nudgeWrapEnter = containerEnter.append("div").attr("class", "nudge-controls-wrap");
+      var nudgeEnter = nudgeWrapEnter.append("div").attr("class", "nudge-outer-rect").on(_pointerPrefix + "down", dragOffset);
+      nudgeEnter.append("div").attr("class", "nudge-inner-rect").append("input").attr("type", "text").attr("aria-label", _t("background.offset_label")).on("change", inputOffset);
+      nudgeWrapEnter.append("div").selectAll("button").data(_directions).enter().append("button").attr("title", function(d2) {
+        return _t("background.nudge.".concat(d2[0]));
+      }).attr("class", function(d2) {
+        return d2[0] + " nudge";
+      }).on("click", function(d3_event, d2) {
+        nudge(d2[1]);
+      });
+      nudgeWrapEnter.append("button").attr("title", _t("background.reset")).attr("class", "nudge-reset disabled").on("click", function(d3_event) {
+        d3_event.preventDefault();
+        resetOffset();
+      }).call(svgIcon("#iD-icon-" + (_mainLocalizer.textDirection() === "rtl" ? "redo" : "undo")));
+      updateValue();
+    }
+    context.background().on("change.backgroundOffset-update", updateValue);
+    return section;
+  }
+
+  // modules/ui/sections/overlay_list.js
+  function uiSectionOverlayList(context) {
+    var section = uiSection("overlay-list", context).label(() => _t.append("background.overlays")).disclosureContent(renderDisclosureContent);
+    var _overlayList = select_default2(null);
+    function setTooltips(selection2) {
+      selection2.each(function(d2, i3, nodes) {
+        var item = select_default2(this).select("label");
+        var span = item.select("span");
+        var placement = i3 < nodes.length / 2 ? "bottom" : "top";
+        var description = d2.description();
+        var isOverflowing = span.property("clientWidth") !== span.property("scrollWidth");
+        item.call(uiTooltip().destroyAny);
+        if (description || isOverflowing) {
+          item.call(
+            uiTooltip().placement(placement).title(() => description || d2.name())
+          );
         }
-      } 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);
-        });
+      });
+    }
+    function updateLayerSelections(selection2) {
+      function active(d2) {
+        return context.background().showsLayer(d2);
       }
-    };
-    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();
+      selection2.selectAll("li").classed("active", active).call(setTooltips).selectAll("input").property("checked", active);
+    }
+    function chooseOverlay(d3_event, d2) {
+      d3_event.preventDefault();
+      context.background().toggleOverlayLayer(d2);
+      _overlayList.call(updateLayerSelections);
+      document.activeElement.blur();
+    }
+    function drawListItems(layerList, type2, change, filter2) {
+      var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter2);
+      var layerLinks = layerList.selectAll("li").data(sources, function(d2) {
+        return d2.name();
+      });
+      layerLinks.exit().remove();
+      var enter = layerLinks.enter().append("li");
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", "layers").on("change", change);
+      label.append("span").each(function(d2) {
+        d2.label()(select_default2(this));
+      });
+      layerList.selectAll("li").sort(sortSources);
+      layerList.call(updateLayerSelections);
+      function sortSources(a2, b2) {
+        return a2.best() && !b2.best() ? -1 : b2.best() && !a2.best() ? 1 : descending(a2.area(), b2.area()) || ascending(a2.name(), b2.name()) || 0;
       }
-      operations.forEach(function(operation) {
-        if (operation.point)
-          operation.point(anchorPoint);
+    }
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".layer-overlay-list").data([0]);
+      _overlayList = container.enter().append("ul").attr("class", "layer-list layer-overlay-list").attr("dir", "auto").merge(container);
+      _overlayList.call(drawListItems, "checkbox", chooseOverlay, function(d2) {
+        return !d2.isHidden() && d2.overlay;
       });
-      _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;
+    }
+    context.map().on(
+      "move.overlay_list",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
   }
 
-  // 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;
+  // modules/ui/panes/background.js
+  function uiPaneBackground(context) {
+    var backgroundPane = uiPane("background", context).key(_t("background.key")).label(_t.append("background.title")).description(_t.append("background.description")).iconName("iD-icon-layers").sections([
+      uiSectionBackgroundList(context),
+      uiSectionOverlayList(context),
+      uiSectionBackgroundDisplayOptions(context),
+      uiSectionBackgroundOffset(context)
+    ]);
+    return backgroundPane;
+  }
+
+  // modules/ui/panes/help.js
+  function uiPaneHelp(context) {
+    var docKeys = [
+      ["help", [
+        "welcome",
+        "open_data_h",
+        "open_data",
+        "before_start_h",
+        "before_start",
+        "open_source_h",
+        "open_source",
+        "open_source_attribution",
+        "open_source_help"
+      ]],
+      ["overview", [
+        "navigation_h",
+        "navigation_drag",
+        "navigation_zoom",
+        "features_h",
+        "features",
+        "nodes_ways"
+      ]],
+      ["editing", [
+        "select_h",
+        "select_left_click",
+        "select_right_click",
+        "select_space",
+        "multiselect_h",
+        "multiselect",
+        "multiselect_shift_click",
+        "multiselect_lasso",
+        "undo_redo_h",
+        "undo_redo",
+        "save_h",
+        "save",
+        "save_validation",
+        "upload_h",
+        "upload",
+        "backups_h",
+        "backups",
+        "keyboard_h",
+        "keyboard"
+      ]],
+      ["feature_editor", [
+        "intro",
+        "definitions",
+        "type_h",
+        "type",
+        "type_picker",
+        "fields_h",
+        "fields_all_fields",
+        "fields_example",
+        "fields_add_field",
+        "tags_h",
+        "tags_all_tags",
+        "tags_resources"
+      ]],
+      ["points", [
+        "intro",
+        "add_point_h",
+        "add_point",
+        "add_point_finish",
+        "move_point_h",
+        "move_point",
+        "delete_point_h",
+        "delete_point",
+        "delete_point_command"
+      ]],
+      ["lines", [
+        "intro",
+        "add_line_h",
+        "add_line",
+        "add_line_draw",
+        "add_line_continue",
+        "add_line_finish",
+        "modify_line_h",
+        "modify_line_dragnode",
+        "modify_line_addnode",
+        "connect_line_h",
+        "connect_line",
+        "connect_line_display",
+        "connect_line_drag",
+        "connect_line_tag",
+        "disconnect_line_h",
+        "disconnect_line_command",
+        "move_line_h",
+        "move_line_command",
+        "move_line_connected",
+        "delete_line_h",
+        "delete_line",
+        "delete_line_command"
+      ]],
+      ["areas", [
+        "intro",
+        "point_or_area_h",
+        "point_or_area",
+        "add_area_h",
+        "add_area_command",
+        "add_area_draw",
+        "add_area_continue",
+        "add_area_finish",
+        "square_area_h",
+        "square_area_command",
+        "modify_area_h",
+        "modify_area_dragnode",
+        "modify_area_addnode",
+        "delete_area_h",
+        "delete_area",
+        "delete_area_command"
+      ]],
+      ["relations", [
+        "intro",
+        "edit_relation_h",
+        "edit_relation",
+        "edit_relation_add",
+        "edit_relation_delete",
+        "maintain_relation_h",
+        "maintain_relation",
+        "relation_types_h",
+        "multipolygon_h",
+        "multipolygon",
+        "multipolygon_create",
+        "multipolygon_merge",
+        "turn_restriction_h",
+        "turn_restriction",
+        "turn_restriction_field",
+        "turn_restriction_editing",
+        "route_h",
+        "route",
+        "route_add",
+        "boundary_h",
+        "boundary",
+        "boundary_add"
+      ]],
+      ["operations", [
+        "intro",
+        "intro_2",
+        "straighten",
+        "orthogonalize",
+        "circularize",
+        "move",
+        "rotate",
+        "reflect",
+        "continue",
+        "reverse",
+        "disconnect",
+        "split",
+        "extract",
+        "merge",
+        "delete",
+        "downgrade",
+        "copy_paste"
+      ]],
+      ["notes", [
+        "intro",
+        "add_note_h",
+        "add_note",
+        "place_note",
+        "move_note",
+        "update_note_h",
+        "update_note",
+        "save_note_h",
+        "save_note"
+      ]],
+      ["imagery", [
+        "intro",
+        "sources_h",
+        "choosing",
+        "sources",
+        "offsets_h",
+        "offset",
+        "offset_change"
+      ]],
+      ["streetlevel", [
+        "intro",
+        "using_h",
+        "using",
+        "photos",
+        "viewer"
+      ]],
+      ["gps", [
+        "intro",
+        "survey",
+        "using_h",
+        "using",
+        "tracing",
+        "upload"
+      ]],
+      ["qa", [
+        "intro",
+        "tools_h",
+        "tools",
+        "issues_h",
+        "issues"
+      ]]
+    ];
+    var headings = {
+      "help.help.open_data_h": 3,
+      "help.help.before_start_h": 3,
+      "help.help.open_source_h": 3,
+      "help.overview.navigation_h": 3,
+      "help.overview.features_h": 3,
+      "help.editing.select_h": 3,
+      "help.editing.multiselect_h": 3,
+      "help.editing.undo_redo_h": 3,
+      "help.editing.save_h": 3,
+      "help.editing.upload_h": 3,
+      "help.editing.backups_h": 3,
+      "help.editing.keyboard_h": 3,
+      "help.feature_editor.type_h": 3,
+      "help.feature_editor.fields_h": 3,
+      "help.feature_editor.tags_h": 3,
+      "help.points.add_point_h": 3,
+      "help.points.move_point_h": 3,
+      "help.points.delete_point_h": 3,
+      "help.lines.add_line_h": 3,
+      "help.lines.modify_line_h": 3,
+      "help.lines.connect_line_h": 3,
+      "help.lines.disconnect_line_h": 3,
+      "help.lines.move_line_h": 3,
+      "help.lines.delete_line_h": 3,
+      "help.areas.point_or_area_h": 3,
+      "help.areas.add_area_h": 3,
+      "help.areas.square_area_h": 3,
+      "help.areas.modify_area_h": 3,
+      "help.areas.delete_area_h": 3,
+      "help.relations.edit_relation_h": 3,
+      "help.relations.maintain_relation_h": 3,
+      "help.relations.relation_types_h": 2,
+      "help.relations.multipolygon_h": 3,
+      "help.relations.turn_restriction_h": 3,
+      "help.relations.route_h": 3,
+      "help.relations.boundary_h": 3,
+      "help.notes.add_note_h": 3,
+      "help.notes.update_note_h": 3,
+      "help.notes.save_note_h": 3,
+      "help.imagery.sources_h": 3,
+      "help.imagery.offsets_h": 3,
+      "help.streetlevel.using_h": 3,
+      "help.gps.using_h": 3,
+      "help.qa.tools_h": 3,
+      "help.qa.issues_h": 3
+    };
+    var docs = docKeys.map(function(key) {
+      var helpkey = "help." + key[0];
+      var helpPaneReplacements = { version: context.version };
+      var text = key[1].reduce(function(all, part) {
+        var subkey = helpkey + "." + part;
+        var depth = headings[subkey];
+        var hhh = depth ? Array(depth + 1).join("#") + " " : "";
+        return all + hhh + helpHtml(subkey, helpPaneReplacements) + "\n\n";
+      }, "");
+      return {
+        title: _t.html(helpkey + ".title"),
+        content: marked(text.trim()).replace(/<code>/g, "<kbd>").replace(/<\/code>/g, "</kbd>")
+      };
+    });
+    var helpPane = uiPane("help", context).key(_t("help.key")).label(_t.append("help.title")).description(_t.append("help.title")).iconName("iD-icon-help");
+    helpPane.renderContent = function(content) {
+      function clickHelp(d2, i3) {
+        var rtl = _mainLocalizer.textDirection() === "rtl";
+        content.property("scrollTop", 0);
+        helpPane.selection().select(".pane-heading h2").html(d2.title);
+        body.html(d2.content);
+        body.selectAll("a").attr("target", "_blank");
+        menuItems.classed("selected", function(m2) {
+          return m2.title === d2.title;
+        });
+        nav.html("");
+        if (rtl) {
+          nav.call(drawNext).call(drawPrevious);
+        } else {
+          nav.call(drawPrevious).call(drawNext);
+        }
+        function drawNext(selection2) {
+          if (i3 < docs.length - 1) {
+            var nextLink = selection2.append("a").attr("href", "#").attr("class", "next").on("click", function(d3_event) {
+              d3_event.preventDefault();
+              clickHelp(docs[i3 + 1], i3 + 1);
+            });
+            nextLink.append("span").html(docs[i3 + 1].title).call(svgIcon(rtl ? "#iD-icon-backward" : "#iD-icon-forward", "inline"));
+          }
+        }
+        function drawPrevious(selection2) {
+          if (i3 > 0) {
+            var prevLink = selection2.append("a").attr("href", "#").attr("class", "previous").on("click", function(d3_event) {
+              d3_event.preventDefault();
+              clickHelp(docs[i3 - 1], i3 - 1);
+            });
+            prevLink.call(svgIcon(rtl ? "#iD-icon-forward" : "#iD-icon-backward", "inline")).append("span").html(docs[i3 - 1].title);
+          }
+        }
+      }
+      function clickWalkthrough(d3_event) {
+        d3_event.preventDefault();
+        if (context.inIntro()) return;
+        context.container().call(uiIntro(context));
+        context.ui().togglePanes();
+      }
+      function clickShortcuts(d3_event) {
+        d3_event.preventDefault();
+        context.container().call(context.ui().shortcuts, true);
+      }
+      var toc = content.append("ul").attr("class", "toc");
+      var menuItems = toc.selectAll("li").data(docs).enter().append("li").append("a").attr("role", "button").attr("href", "#").html(function(d2) {
+        return d2.title;
+      }).on("click", function(d3_event, d2) {
+        d3_event.preventDefault();
+        clickHelp(d2, docs.indexOf(d2));
+      });
+      var shortcuts = toc.append("li").attr("class", "shortcuts").call(
+        uiTooltip().title(() => _t.append("shortcuts.tooltip")).keys(["?"]).placement("top")
+      ).append("a").attr("href", "#").on("click", clickShortcuts);
+      shortcuts.append("div").call(_t.append("shortcuts.title"));
+      var walkthrough = toc.append("li").attr("class", "walkthrough").append("a").attr("href", "#").on("click", clickWalkthrough);
+      walkthrough.append("svg").attr("class", "logo logo-walkthrough").append("use").attr("xlink:href", "#iD-logo-walkthrough");
+      walkthrough.append("div").call(_t.append("splash.walkthrough"));
+      var helpContent = content.append("div").attr("class", "left-content");
+      var body = helpContent.append("div").attr("class", "body");
+      var nav = helpContent.append("div").attr("class", "nav");
+      clickHelp(docs[0], 0);
+    };
+    return helpPane;
+  }
+
+  // modules/ui/sections/validation_issues.js
+  function uiSectionValidationIssues(id2, severity, context) {
+    var _issues = [];
+    var section = uiSection(id2, context).label(function() {
+      if (!_issues) return "";
+      var issueCountText = _issues.length > 1e3 ? "1000+" : String(_issues.length);
+      return _t.append("inspector.title_count", { title: _t("issues." + severity + "s.list_title"), count: issueCountText });
+    }).disclosureContent(renderDisclosureContent).shouldDisplay(function() {
+      return _issues && _issues.length;
+    });
+    function getOptions() {
+      return {
+        what: corePreferences("validate-what") || "edited",
+        where: corePreferences("validate-where") || "all"
+      };
+    }
+    function reloadIssues() {
+      _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
+    }
+    function renderDisclosureContent(selection2) {
+      var center = context.map().center();
+      var graph = context.graph();
+      var issues = _issues.map(function withDistance(issue) {
+        var extent = issue.extent(graph);
+        var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
+        return Object.assign(issue, { dist });
+      }).sort(function byDistance(a2, b2) {
+        return a2.dist - b2.dist;
+      });
+      issues = issues.slice(0, 1e3);
+      selection2.call(drawIssuesList, issues);
+    }
+    function drawIssuesList(selection2, issues) {
+      var list2 = selection2.selectAll(".issues-list").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "layer-list issues-list " + severity + "s-list").merge(list2);
+      var items = list2.selectAll("li").data(issues, function(d2) {
+        return d2.key;
+      });
+      items.exit().remove();
+      var itemsEnter = items.enter().append("li").attr("class", function(d2) {
+        return "issue severity-" + d2.severity;
+      });
+      var labelsEnter = itemsEnter.append("button").attr("class", "issue-label").on("click", function(d3_event, d2) {
+        context.validator().focusIssue(d2);
+      }).on("mouseover", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, true, context);
+      }).on("mouseout", function(d3_event, d2) {
+        utilHighlightEntities(d2.entityIds, false, context);
+      });
+      var textEnter = labelsEnter.append("span").attr("class", "issue-text");
+      textEnter.append("span").attr("class", "issue-icon").each(function(d2) {
+        var iconName = "#iD-icon-" + (d2.severity === "warning" ? "alert" : "error");
+        select_default2(this).call(svgIcon(iconName));
+      });
+      textEnter.append("span").attr("class", "issue-message");
+      items = items.merge(itemsEnter).order();
+      items.selectAll(".issue-message").text("").each(function(d2) {
+        return d2.message(context)(select_default2(this));
+      });
+    }
+    context.validator().on("validated.uiSectionValidationIssues" + id2, function() {
+      window.requestIdleCallback(function() {
+        reloadIssues();
+        section.reRender();
+      });
+    });
+    context.map().on(
+      "move.uiSectionValidationIssues" + id2,
+      debounce_default(function() {
+        window.requestIdleCallback(function() {
+          if (getOptions().where === "visible") {
+            reloadIssues();
+          }
+          section.reRender();
+        });
+      }, 1e3)
+    );
+    return section;
+  }
+
+  // modules/ui/sections/validation_options.js
+  function uiSectionValidationOptions(context) {
+    var section = uiSection("issues-options", context).content(renderContent);
+    function renderContent(selection2) {
+      var container = selection2.selectAll(".issues-options-container").data([0]);
+      container = container.enter().append("div").attr("class", "issues-options-container").merge(container);
+      var data = [
+        { key: "what", values: ["edited", "all"] },
+        { key: "where", values: ["visible", "all"] }
+      ];
+      var options2 = container.selectAll(".issues-option").data(data, function(d2) {
+        return d2.key;
+      });
+      var optionsEnter = options2.enter().append("div").attr("class", function(d2) {
+        return "issues-option issues-option-" + d2.key;
+      });
+      optionsEnter.append("div").attr("class", "issues-option-title").html(function(d2) {
+        return _t.html("issues.options." + d2.key + ".title");
+      });
+      var valuesEnter = optionsEnter.selectAll("label").data(function(d2) {
+        return d2.values.map(function(val) {
+          return { value: val, key: d2.key };
+        });
+      }).enter().append("label");
+      valuesEnter.append("input").attr("type", "radio").attr("name", function(d2) {
+        return "issues-option-" + d2.key;
+      }).attr("value", function(d2) {
+        return d2.value;
+      }).property("checked", function(d2) {
+        return getOptions()[d2.key] === d2.value;
+      }).on("change", function(d3_event, d2) {
+        updateOptionValue(d3_event, d2.key, d2.value);
+      });
+      valuesEnter.append("span").html(function(d2) {
+        return _t.html("issues.options." + d2.key + "." + d2.value);
+      });
+    }
+    function getOptions() {
+      return {
+        what: corePreferences("validate-what") || "edited",
+        // 'all', 'edited'
+        where: corePreferences("validate-where") || "all"
+        // 'all', 'visible'
+      };
+    }
+    function updateOptionValue(d3_event, d2, val) {
+      if (!val && d3_event && d3_event.target) {
+        val = d3_event.target.value;
+      }
+      corePreferences("validate-" + d2, val);
+      context.validator().validate();
+    }
+    return section;
+  }
+
+  // modules/ui/sections/validation_rules.js
+  function uiSectionValidationRules(context) {
+    var MINSQUARE = 0;
+    var MAXSQUARE = 20;
+    var DEFAULTSQUARE = 5;
+    var section = uiSection("issues-rules", context).disclosureContent(renderDisclosureContent).label(() => _t.append("issues.rules.title"));
+    var _ruleKeys = context.validator().getRuleKeys().filter(function(key) {
+      return key !== "maprules";
+    }).sort(function(key1, key2) {
+      return _t("issues." + key1 + ".title") < _t("issues." + key2 + ".title") ? -1 : 1;
+    });
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".issues-rulelist-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "issues-rulelist-container");
+      containerEnter.append("ul").attr("class", "layer-list issue-rules-list");
+      var ruleLinks = containerEnter.append("div").attr("class", "issue-rules-links section-footer");
+      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.validator().disableRules(_ruleKeys);
+      });
+      ruleLinks.append("a").attr("class", "issue-rules-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.validator().disableRules([]);
+      });
+      container = container.merge(containerEnter);
+      container.selectAll(".issue-rules-list").call(drawListItems, _ruleKeys, "checkbox", "rule", toggleRule, isRuleEnabled);
+    }
+    function drawListItems(selection2, data, type2, name, change, active) {
+      var items = selection2.selectAll("li").data(data);
+      items.exit().remove();
+      var enter = items.enter().append("li");
+      if (name === "rule") {
+        enter.call(
+          uiTooltip().title(function(d2) {
+            return _t.append("issues." + d2 + ".tip");
+          }).placement("top")
+        );
+      }
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
+      label.append("span").html(function(d2) {
+        var params = {};
+        if (d2 === "unsquare_way") {
+          params.val = { html: '<span class="square-degrees"></span>' };
+        }
+        return _t.html("issues." + d2 + ".title", params);
+      });
+      items = items.merge(enter);
+      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
+      var degStr = corePreferences("validate-square-degrees");
+      if (degStr === null) {
+        degStr = DEFAULTSQUARE.toString();
+      }
+      var span = items.selectAll(".square-degrees");
+      var input = span.selectAll(".square-degrees-input").data([0]);
+      input.enter().append("input").attr("type", "number").attr("min", MINSQUARE.toString()).attr("max", MAXSQUARE.toString()).attr("step", "0.5").attr("class", "square-degrees-input").call(utilNoAuto).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        this.select();
+      }).on("keyup", function(d3_event) {
+        if (d3_event.keyCode === 13) {
+          this.blur();
+          this.select();
+        }
+      }).on("blur", changeSquare).merge(input).property("value", degStr);
+    }
+    function changeSquare() {
+      var input = select_default2(this);
+      var degStr = utilGetSetValue(input).trim();
+      var degNum = Number(degStr);
+      if (!isFinite(degNum)) {
+        degNum = DEFAULTSQUARE;
+      } else if (degNum > MAXSQUARE) {
+        degNum = MAXSQUARE;
+      } else if (degNum < MINSQUARE) {
+        degNum = MINSQUARE;
+      }
+      degNum = Math.round(degNum * 10) / 10;
+      degStr = degNum.toString();
+      input.property("value", degStr);
+      corePreferences("validate-square-degrees", degStr);
+      context.validator().revalidateUnsquare();
+    }
+    function isRuleEnabled(d2) {
+      return context.validator().isRuleEnabled(d2);
+    }
+    function toggleRule(d3_event, d2) {
+      context.validator().toggleRule(d2);
+    }
+    context.validator().on("validated.uiSectionValidationRules", function() {
+      window.requestIdleCallback(section.reRender);
+    });
+    return section;
+  }
+
+  // modules/ui/sections/validation_status.js
+  function uiSectionValidationStatus(context) {
+    var section = uiSection("issues-status", context).content(renderContent).shouldDisplay(function() {
+      var issues = context.validator().getIssues(getOptions());
+      return issues.length === 0;
+    });
+    function getOptions() {
+      return {
+        what: corePreferences("validate-what") || "edited",
+        where: corePreferences("validate-where") || "all"
+      };
+    }
+    function renderContent(selection2) {
+      var box = selection2.selectAll(".box").data([0]);
+      var boxEnter = box.enter().append("div").attr("class", "box");
+      boxEnter.append("div").call(svgIcon("#iD-icon-apply", "pre-text"));
+      var noIssuesMessage = boxEnter.append("span");
+      noIssuesMessage.append("strong").attr("class", "message");
+      noIssuesMessage.append("br");
+      noIssuesMessage.append("span").attr("class", "details");
+      renderIgnoredIssuesReset(selection2);
+      setNoIssuesText(selection2);
+    }
+    function renderIgnoredIssuesReset(selection2) {
+      var ignoredIssues = context.validator().getIssues({ what: "all", where: "all", includeDisabledRules: true, includeIgnored: "only" });
+      var resetIgnored = selection2.selectAll(".reset-ignored").data(ignoredIssues.length ? [0] : []);
+      resetIgnored.exit().remove();
+      var resetIgnoredEnter = resetIgnored.enter().append("div").attr("class", "reset-ignored section-footer");
+      resetIgnoredEnter.append("a").attr("href", "#");
+      resetIgnored = resetIgnored.merge(resetIgnoredEnter);
+      resetIgnored.select("a").html(_t.html("inspector.title_count", { title: { html: _t.html("issues.reset_ignored") }, count: ignoredIssues.length }));
+      resetIgnored.on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.validator().resetIgnoredIssues();
+      });
+    }
+    function setNoIssuesText(selection2) {
+      var opts = getOptions();
+      function checkForHiddenIssues(cases) {
+        for (var type2 in cases) {
+          var hiddenOpts = cases[type2];
+          var hiddenIssues = context.validator().getIssues(hiddenOpts);
+          if (hiddenIssues.length) {
+            selection2.select(".box .details").html("").call(_t.append(
+              "issues.no_issues.hidden_issues." + type2,
+              { count: hiddenIssues.length.toString() }
+            ));
+            return;
+          }
+        }
+        selection2.select(".box .details").html("").call(_t.append("issues.no_issues.hidden_issues.none"));
+      }
+      var messageType;
+      if (opts.what === "edited" && opts.where === "visible") {
+        messageType = "edits_in_view";
+        checkForHiddenIssues({
+          elsewhere: { what: "edited", where: "all" },
+          everything_else: { what: "all", where: "visible" },
+          disabled_rules: { what: "edited", where: "visible", includeDisabledRules: "only" },
+          everything_else_elsewhere: { what: "all", where: "all" },
+          disabled_rules_elsewhere: { what: "edited", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "edited", where: "visible", includeIgnored: "only" },
+          ignored_issues_elsewhere: { what: "edited", where: "all", includeIgnored: "only" }
+        });
+      } else if (opts.what === "edited" && opts.where === "all") {
+        messageType = "edits";
+        checkForHiddenIssues({
+          everything_else: { what: "all", where: "all" },
+          disabled_rules: { what: "edited", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "edited", where: "all", includeIgnored: "only" }
+        });
+      } else if (opts.what === "all" && opts.where === "visible") {
+        messageType = "everything_in_view";
+        checkForHiddenIssues({
+          elsewhere: { what: "all", where: "all" },
+          disabled_rules: { what: "all", where: "visible", includeDisabledRules: "only" },
+          disabled_rules_elsewhere: { what: "all", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "all", where: "visible", includeIgnored: "only" },
+          ignored_issues_elsewhere: { what: "all", where: "all", includeIgnored: "only" }
+        });
+      } else if (opts.what === "all" && opts.where === "all") {
+        messageType = "everything";
+        checkForHiddenIssues({
+          disabled_rules: { what: "all", where: "all", includeDisabledRules: "only" },
+          ignored_issues: { what: "all", where: "all", includeIgnored: "only" }
+        });
+      }
+      if (opts.what === "edited" && context.history().difference().summary().length === 0) {
+        messageType = "no_edits";
+      }
+      selection2.select(".box .message").html("").call(_t.append("issues.no_issues.message." + messageType));
+    }
+    context.validator().on("validated.uiSectionValidationStatus", function() {
+      window.requestIdleCallback(section.reRender);
+    });
+    context.map().on(
+      "move.uiSectionValidationStatus",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
+  }
+
+  // modules/ui/panes/issues.js
+  function uiPaneIssues(context) {
+    var issuesPane = uiPane("issues", context).key(_t("issues.key")).label(_t.append("issues.title")).description(_t.append("issues.title")).iconName("iD-icon-alert").sections([
+      uiSectionValidationOptions(context),
+      uiSectionValidationStatus(context),
+      uiSectionValidationIssues("issues-errors", "error", context),
+      uiSectionValidationIssues("issues-warnings", "warning", context),
+      uiSectionValidationRules(context)
+    ]);
+    return issuesPane;
+  }
+
+  // modules/ui/settings/custom_data.js
+  function uiSettingsCustomData(context) {
+    var dispatch14 = dispatch_default("change");
+    function render(selection2) {
+      var dataLayer = context.layers().layer("data");
+      var _origSettings = {
+        fileList: dataLayer && dataLayer.fileList() || null,
+        url: corePreferences("settings-custom-data-url")
+      };
+      var _currSettings = {
+        fileList: dataLayer && dataLayer.fileList() || null
+        // url: prefs('settings-custom-data-url')
+      };
+      var modal = uiConfirm(selection2).okButton();
+      modal.classed("settings-modal settings-custom-data", true);
+      modal.select(".modal-section.header").append("h3").call(_t.append("settings.custom_data.header"));
+      var textSection = modal.select(".modal-section.message-text");
+      textSection.append("pre").attr("class", "instructions-file").call(_t.append("settings.custom_data.file.instructions"));
+      textSection.append("input").attr("class", "field-file").attr("type", "file").attr("accept", ".gpx,.kml,.geojson,.json,application/gpx+xml,application/vnd.google-earth.kml+xml,application/geo+json,application/json").property("files", _currSettings.fileList).on("change", function(d3_event) {
+        var files = d3_event.target.files;
+        if (files && files.length) {
+          _currSettings.url = "";
+          textSection.select(".field-url").property("value", "");
+          _currSettings.fileList = files;
+        } else {
+          _currSettings.fileList = null;
+        }
+      });
+      textSection.append("h4").call(_t.append("settings.custom_data.or"));
+      textSection.append("pre").attr("class", "instructions-url").call(_t.append("settings.custom_data.url.instructions"));
+      textSection.append("textarea").attr("class", "field-url").attr("placeholder", _t("settings.custom_data.url.placeholder")).call(utilNoAuto).property("value", _currSettings.url);
+      var buttonSection = modal.select(".modal-section.buttons");
+      buttonSection.insert("button", ".ok-button").attr("class", "button cancel-button secondary-action").call(_t.append("confirm.cancel"));
+      buttonSection.select(".cancel-button").on("click.cancel", clickCancel);
+      buttonSection.select(".ok-button").attr("disabled", isSaveDisabled).on("click.save", clickSave);
+      function isSaveDisabled() {
+        return null;
+      }
+      function clickCancel() {
+        textSection.select(".field-url").property("value", _origSettings.url);
+        corePreferences("settings-custom-data-url", _origSettings.url);
+        this.blur();
+        modal.close();
+      }
+      function clickSave() {
+        _currSettings.url = textSection.select(".field-url").property("value").trim();
+        if (_currSettings.url) {
+          _currSettings.fileList = null;
+        }
+        if (_currSettings.fileList) {
+          _currSettings.url = "";
+        }
+        corePreferences("settings-custom-data-url", _currSettings.url);
+        this.blur();
+        modal.close();
+        dispatch14.call("change", this, _currSettings);
+      }
+    }
+    return utilRebind(render, dispatch14, "on");
+  }
+
+  // modules/ui/sections/data_layers.js
+  function uiSectionDataLayers(context) {
+    var settingsCustomData = uiSettingsCustomData(context).on("change", customChanged);
+    var layers = context.layers();
+    var section = uiSection("data-layers", context).label(() => _t.append("map_data.data_layers")).disclosureContent(renderDisclosureContent);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".data-layer-container").data([0]);
+      container.enter().append("div").attr("class", "data-layer-container").merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems).call(drawPanelItems);
+    }
+    function showsLayer(which) {
+      var layer = layers.layer(which);
+      if (layer) {
+        return layer.enabled();
+      }
+      return false;
+    }
+    function setLayer(which, enabled) {
+      var mode = context.mode();
+      if (mode && /^draw/.test(mode.id)) return;
+      var layer = layers.layer(which);
+      if (layer) {
+        layer.enabled(enabled);
+        if (!enabled && (which === "osm" || which === "notes")) {
+          context.enter(modeBrowse(context));
+        }
+      }
+    }
+    function toggleLayer(which) {
+      setLayer(which, !showsLayer(which));
+    }
+    function drawOsmItems(selection2) {
+      var osmKeys = ["osm", "notes"];
+      var osmLayers = layers.all().filter(function(obj) {
+        return osmKeys.indexOf(obj.id) !== -1;
+      });
+      var ul = selection2.selectAll(".layer-list-osm").data([0]);
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-osm").merge(ul);
+      var li = ul.selectAll(".list-item").data(osmLayers);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item list-item-" + d2.id;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        if (d2.id === "osm") {
+          select_default2(this).call(
+            uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).keys([uiCmd("\u2325" + _t("area_fill.wireframe.key"))]).placement("bottom")
+          );
+        } else {
+          select_default2(this).call(
+            uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).placement("bottom")
+          );
+        }
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        toggleLayer(d2.id);
+      });
+      labelEnter.append("span").html(function(d2) {
+        return _t.html("map_data.layers." + d2.id + ".title");
+      });
+      li.merge(liEnter).classed("active", function(d2) {
+        return d2.layer.enabled();
+      }).selectAll("input").property("checked", function(d2) {
+        return d2.layer.enabled();
+      });
+    }
+    function drawQAItems(selection2) {
+      var qaKeys = ["keepRight", "osmose"];
+      var qaLayers = layers.all().filter(function(obj) {
+        return qaKeys.indexOf(obj.id) !== -1;
+      });
+      var ul = selection2.selectAll(".layer-list-qa").data([0]);
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-qa").merge(ul);
+      var li = ul.selectAll(".list-item").data(qaLayers);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item list-item-" + d2.id;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("map_data.layers." + d2.id + ".tooltip")).placement("bottom")
+        );
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        toggleLayer(d2.id);
+      });
+      labelEnter.append("span").each(function(d2) {
+        _t.append("map_data.layers." + d2.id + ".title")(select_default2(this));
+      });
+      li.merge(liEnter).classed("active", function(d2) {
+        return d2.layer.enabled();
+      }).selectAll("input").property("checked", function(d2) {
+        return d2.layer.enabled();
+      });
+    }
+    function drawVectorItems(selection2) {
+      var dataLayer = layers.layer("data");
+      var vtData = [
+        {
+          name: "Detroit Neighborhoods/Parks",
+          src: "neighborhoods-parks",
+          tooltip: "Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.",
+          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmur6x34562qp9iv1u3ksf-54hev,jonahadkins.cjksmqxdx33jj2wp90xd9x2md-4e5y2/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
+        },
+        {
+          name: "Detroit Composite POIs",
+          src: "composite-poi",
+          tooltip: "Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.",
+          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmm6a02sli31myxhsr7zf3-2sw8h/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
+        },
+        {
+          name: "Detroit All-The-Places POIs",
+          src: "alltheplaces-poi",
+          tooltip: "Public domain business location data created by web scrapers.",
+          template: "https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmswgk340g2vo06p1w9w0j-8fjjc/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA"
+        }
+      ];
+      var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
+      var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
+      var container = selection2.selectAll(".vectortile-container").data(showVectorItems ? [0] : []);
+      container.exit().remove();
+      var containerEnter = container.enter().append("div").attr("class", "vectortile-container");
+      containerEnter.append("h4").attr("class", "vectortile-header").text("Detroit Vector Tiles (Beta)");
+      containerEnter.append("ul").attr("class", "layer-list layer-list-vectortile");
+      containerEnter.append("div").attr("class", "vectortile-footer").append("a").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmus/detroit-mapping-challenge").append("span").text("About these layers");
+      container = container.merge(containerEnter);
+      var ul = container.selectAll(".layer-list-vectortile");
+      var li = ul.selectAll(".list-item").data(vtData);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item list-item-" + d2.src;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(d2.tooltip).placement("top")
+        );
+      });
+      labelEnter.append("input").attr("type", "radio").attr("name", "vectortile").on("change", selectVTLayer);
+      labelEnter.append("span").text(function(d2) {
+        return d2.name;
+      });
+      li.merge(liEnter).classed("active", isVTLayerSelected).selectAll("input").property("checked", isVTLayerSelected);
+      function isVTLayerSelected(d2) {
+        return dataLayer && dataLayer.template() === d2.template;
+      }
+      function selectVTLayer(d3_event, d2) {
+        corePreferences("settings-custom-data-url", d2.template);
+        if (dataLayer) {
+          dataLayer.template(d2.template, d2.src);
+          dataLayer.enabled(true);
+        }
+      }
+    }
+    function drawCustomDataItems(selection2) {
+      var dataLayer = layers.layer("data");
+      var hasData = dataLayer && dataLayer.hasData();
+      var showsData = hasData && dataLayer.enabled();
+      var ul = selection2.selectAll(".layer-list-data").data(dataLayer ? [0] : []);
+      ul.exit().remove();
+      var ulEnter = ul.enter().append("ul").attr("class", "layer-list layer-list-data");
+      var liEnter = ulEnter.append("li").attr("class", "list-item-data");
+      var labelEnter = liEnter.append("label").call(
+        uiTooltip().title(() => _t.append("map_data.layers.custom.tooltip")).placement("top")
+      );
+      labelEnter.append("input").attr("type", "checkbox").on("change", function() {
+        toggleLayer("data");
+      });
+      labelEnter.append("span").call(_t.append("map_data.layers.custom.title"));
+      liEnter.append("button").attr("class", "open-data-options").call(
+        uiTooltip().title(() => _t.append("settings.custom_data.tooltip")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        editCustom();
+      }).call(svgIcon("#iD-icon-more"));
+      liEnter.append("button").attr("class", "zoom-to-data").call(
+        uiTooltip().title(() => _t.append("map_data.layers.custom.zoom")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        if (select_default2(this).classed("disabled")) return;
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        dataLayer.fitZoom();
+      }).call(svgIcon("#iD-icon-framed-dot", "monochrome"));
+      ul = ul.merge(ulEnter);
+      ul.selectAll(".list-item-data").classed("active", showsData).selectAll("label").classed("deemphasize", !hasData).selectAll("input").property("disabled", !hasData).property("checked", showsData);
+      ul.selectAll("button.zoom-to-data").classed("disabled", !hasData);
+    }
+    function editCustom() {
+      context.container().call(settingsCustomData);
+    }
+    function customChanged(d2) {
+      var dataLayer = layers.layer("data");
+      if (d2 && d2.url) {
+        dataLayer.url(d2.url);
+      } else if (d2 && d2.fileList) {
+        dataLayer.fileList(d2.fileList);
+      }
+    }
+    function drawPanelItems(selection2) {
+      var panelsListEnter = selection2.selectAll(".md-extras-list").data([0]).enter().append("ul").attr("class", "layer-list md-extras-list");
+      var historyPanelLabelEnter = panelsListEnter.append("li").attr("class", "history-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("map_data.history_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.history.key"))]).placement("top")
+      );
+      historyPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("history");
+      });
+      historyPanelLabelEnter.append("span").call(_t.append("map_data.history_panel.title"));
+      var measurementPanelLabelEnter = panelsListEnter.append("li").attr("class", "measurement-panel-toggle-item").append("label").call(
+        uiTooltip().title(() => _t.append("map_data.measurement_panel.tooltip")).keys([uiCmd("\u2318\u21E7" + _t("info_panels.measurement.key"))]).placement("top")
+      );
+      measurementPanelLabelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event) {
+        d3_event.preventDefault();
+        context.ui().info.toggle("measurement");
+      });
+      measurementPanelLabelEnter.append("span").call(_t.append("map_data.measurement_panel.title"));
+    }
+    context.layers().on("change.uiSectionDataLayers", section.reRender);
+    context.map().on(
+      "move.uiSectionDataLayers",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
+  }
+
+  // modules/ui/sections/map_features.js
+  function uiSectionMapFeatures(context) {
+    var _features = context.features().keys();
+    var section = uiSection("map-features", context).label(() => _t.append("map_data.map_features")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".layer-feature-list-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "layer-feature-list-container");
+      containerEnter.append("ul").attr("class", "layer-list layer-feature-list");
+      var footer = containerEnter.append("div").attr("class", "feature-list-links section-footer");
+      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.disable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.features().disableAll();
+      });
+      footer.append("a").attr("class", "feature-list-link").attr("role", "button").attr("href", "#").call(_t.append("issues.enable_all")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        context.features().enableAll();
+      });
+      container = container.merge(containerEnter);
+      container.selectAll(".layer-feature-list").call(drawListItems, _features, "checkbox", "feature", clickFeature, showsFeature);
+    }
+    function drawListItems(selection2, data, type2, name, change, active) {
+      var items = selection2.selectAll("li").data(data);
+      items.exit().remove();
+      var enter = items.enter().append("li").call(
+        uiTooltip().title(function(d2) {
+          var tip = _t.append(name + "." + d2 + ".tooltip");
+          if (autoHiddenFeature(d2)) {
+            var msg = showsLayer("osm") ? _t.append("map_data.autohidden") : _t.append("map_data.osmhidden");
+            return (selection3) => {
+              selection3.call(tip);
+              selection3.append("div").call(msg);
+            };
+          }
+          return tip;
+        }).placement("top")
+      );
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
+      label.append("span").html(function(d2) {
+        return _t.html(name + "." + d2 + ".description");
+      });
+      items = items.merge(enter);
+      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", autoHiddenFeature);
+    }
+    function autoHiddenFeature(d2) {
+      return context.features().autoHidden(d2);
+    }
+    function showsFeature(d2) {
+      return context.features().enabled(d2);
+    }
+    function clickFeature(d3_event, d2) {
+      context.features().toggle(d2);
+    }
+    function showsLayer(id2) {
+      var layer = context.layers().layer(id2);
+      return layer && layer.enabled();
+    }
+    context.features().on("change.map_features", section.reRender);
+    return section;
+  }
+
+  // modules/ui/sections/map_style_options.js
+  function uiSectionMapStyleOptions(context) {
+    var section = uiSection("fill-area", context).label(() => _t.append("map_data.style_options")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".layer-fill-list").data([0]);
+      container.enter().append("ul").attr("class", "layer-list layer-fill-list").merge(container).call(drawListItems, context.map().areaFillOptions, "radio", "area_fill", setFill, isActiveFill);
+      var container2 = selection2.selectAll(".layer-visual-diff-list").data([0]);
+      container2.enter().append("ul").attr("class", "layer-list layer-visual-diff-list").merge(container2).call(drawListItems, ["highlight_edits"], "checkbox", "visual_diff", toggleHighlightEdited, function() {
+        return context.surface().classed("highlight-edited");
+      });
+    }
+    function drawListItems(selection2, data, type2, name, change, active) {
+      var items = selection2.selectAll("li").data(data);
+      items.exit().remove();
+      var enter = items.enter().append("li").call(
+        uiTooltip().title(function(d2) {
+          return _t.append(name + "." + d2 + ".tooltip");
+        }).keys(function(d2) {
+          var key = d2 === "wireframe" ? _t("area_fill.wireframe.key") : null;
+          if (d2 === "highlight_edits") key = _t("map_data.highlight_edits.key");
+          return key ? [key] : null;
+        }).placement("top")
+      );
+      var label = enter.append("label");
+      label.append("input").attr("type", type2).attr("name", name).on("change", change);
+      label.append("span").html(function(d2) {
+        return _t.html(name + "." + d2 + ".description");
+      });
+      items = items.merge(enter);
+      items.classed("active", active).selectAll("input").property("checked", active).property("indeterminate", false);
+    }
+    function isActiveFill(d2) {
+      return context.map().activeAreaFill() === d2;
+    }
+    function toggleHighlightEdited(d3_event) {
+      d3_event.preventDefault();
+      context.map().toggleHighlightEdited();
+    }
+    function setFill(d3_event, d2) {
+      context.map().activeAreaFill(d2);
+    }
+    context.map().on("changeHighlighting.ui_style, changeAreaFill.ui_style", section.reRender);
+    return section;
+  }
+
+  // modules/ui/settings/local_photos.js
+  function uiSettingsLocalPhotos(context) {
+    var dispatch14 = dispatch_default("change");
+    var photoLayer = context.layers().layer("local-photos");
+    var modal;
+    function render(selection2) {
+      modal = uiConfirm(selection2).okButton();
+      modal.classed("settings-modal settings-local-photos", true);
+      modal.select(".modal-section.header").append("h3").call(_t.append("local_photos.header"));
+      modal.select(".modal-section.message-text").append("div").classed("local-photos", true);
+      var instructionsSection = modal.select(".modal-section.message-text .local-photos").append("div").classed("instructions", true);
+      instructionsSection.append("p").classed("instructions-local-photos", true).call(_t.append("local_photos.file.instructions"));
+      instructionsSection.append("input").classed("field-file", true).attr("type", "file").attr("multiple", "multiple").attr("accept", ".jpg,.jpeg,.png,image/png,image/jpeg").style("visibility", "hidden").attr("id", "local-photo-files").on("change", function(d3_event) {
+        var files = d3_event.target.files;
+        if (files && files.length) {
+          photoList.select("ul").append("li").classed("placeholder", true).append("div");
+          dispatch14.call("change", this, files);
+        }
+        d3_event.target.value = null;
+      });
+      instructionsSection.append("label").attr("for", "local-photo-files").classed("button", true).call(_t.append("local_photos.file.label"));
+      const photoList = modal.select(".modal-section.message-text .local-photos").append("div").append("div").classed("list-local-photos", true);
+      photoList.append("ul");
+      updatePhotoList(photoList.select("ul"));
+      context.layers().on("change", () => updatePhotoList(photoList.select("ul")));
+    }
+    function updatePhotoList(container) {
+      var _a3;
+      function locationUnavailable(d2) {
+        return !(isArray_default(d2.loc) && isNumber_default(d2.loc[0]) && isNumber_default(d2.loc[1]));
+      }
+      container.selectAll("li.placeholder").remove();
+      let selection2 = container.selectAll("li").data((_a3 = photoLayer.getPhotos()) != null ? _a3 : [], (d2) => d2.id);
+      selection2.exit().remove();
+      const selectionEnter = selection2.enter().append("li");
+      selectionEnter.append("span").classed("filename", true);
+      selectionEnter.append("button").classed("form-field-button zoom-to-data", true).attr("title", _t("local_photos.zoom_single")).call(svgIcon("#iD-icon-framed-dot"));
+      selectionEnter.append("button").classed("form-field-button no-geolocation", true).call(svgIcon("#iD-icon-alert")).call(
+        uiTooltip().title(() => _t.append("local_photos.no_geolocation.tooltip")).placement("left")
+      );
+      selectionEnter.append("button").classed("form-field-button remove", true).attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
+      selection2 = selection2.merge(selectionEnter);
+      selection2.classed("invalid", locationUnavailable);
+      selection2.select("span.filename").text((d2) => d2.name).attr("title", (d2) => d2.name);
+      selection2.select("span.filename").on("click", (d3_event, d2) => {
+        photoLayer.openPhoto(d3_event, d2, false);
+      });
+      selection2.select("button.zoom-to-data").on("click", (d3_event, d2) => {
+        photoLayer.openPhoto(d3_event, d2, true);
+      });
+      selection2.select("button.remove").on("click", (d3_event, d2) => {
+        photoLayer.removePhoto(d2.id);
+        updatePhotoList(container);
+      });
+    }
+    return utilRebind(render, dispatch14, "on");
+  }
+
+  // modules/ui/sections/photo_overlays.js
+  function uiSectionPhotoOverlays(context) {
+    var settingsLocalPhotos = uiSettingsLocalPhotos(context).on("change", localPhotosChanged);
+    var layers = context.layers();
+    var section = uiSection("photo-overlays", context).label(() => _t.append("photo_overlays.title")).disclosureContent(renderDisclosureContent).expandedByDefault(false);
+    function renderDisclosureContent(selection2) {
+      var container = selection2.selectAll(".photo-overlay-container").data([0]);
+      container.enter().append("div").attr("class", "photo-overlay-container").merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter).call(drawLocalPhotos);
+    }
+    function drawPhotoItems(selection2) {
+      var photoKeys = context.photos().overlayLayerIDs();
+      var photoLayers = layers.all().filter(function(obj) {
+        return photoKeys.indexOf(obj.id) !== -1;
+      });
+      var data = photoLayers.filter(function(obj) {
+        if (!obj.layer.supported()) return false;
+        if (layerEnabled(obj)) return true;
+        if (typeof obj.layer.validHere === "function") {
+          return obj.layer.validHere(context.map().extent(), context.map().zoom());
+        }
+        return true;
+      });
+      function layerSupported(d2) {
+        return d2.layer && d2.layer.supported();
+      }
+      function layerEnabled(d2) {
+        return layerSupported(d2) && d2.layer.enabled();
+      }
+      function layerRendered(d2) {
+        var _a3, _b3, _c;
+        return (_c = (_b3 = (_a3 = d2.layer).rendered) == null ? void 0 : _b3.call(_a3, context.map().zoom())) != null ? _c : true;
+      }
+      var ul = selection2.selectAll(".layer-list-photos").data([0]);
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-photos").merge(ul);
+      var li = ul.selectAll(".list-item-photos").data(data, (d2) => d2.id);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        var classes = "list-item-photos list-item-" + d2.id;
+        if (d2.id === "mapillary-signs" || d2.id === "mapillary-map-features") {
+          classes += " indented";
+        }
+        return classes;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        var titleID;
+        if (d2.id === "mapillary-signs") titleID = "mapillary.signs.tooltip";
+        else if (d2.id === "mapillary") titleID = "mapillary_images.tooltip";
+        else if (d2.id === "kartaview") titleID = "kartaview_images.tooltip";
+        else titleID = d2.id.replace(/-/g, "_") + ".tooltip";
+        select_default2(this).call(
+          uiTooltip().title(() => {
+            if (!layerRendered(d2)) {
+              return _t.append("street_side.minzoom_tooltip");
+            } else {
+              return _t.append(titleID);
+            }
+          }).placement("top")
+        );
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        toggleLayer(d2.id);
+      });
+      labelEnter.append("span").html(function(d2) {
+        var id2 = d2.id;
+        if (id2 === "mapillary-signs") id2 = "photo_overlays.traffic_signs";
+        return _t.html(id2.replace(/-/g, "_") + ".title");
+      });
+      li.merge(liEnter).classed("active", layerEnabled).selectAll("input").property("disabled", (d2) => !layerRendered(d2)).property("checked", layerEnabled);
+    }
+    function drawPhotoTypeItems(selection2) {
+      var data = context.photos().allPhotoTypes();
+      function typeEnabled(d2) {
+        return context.photos().showsPhotoType(d2);
+      }
+      var ul = selection2.selectAll(".layer-list-photo-types").data([0]);
+      ul.exit().remove();
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-photo-types").merge(ul);
+      var li = ul.selectAll(".list-item-photo-types").data(context.photos().shouldFilterByPhotoType() ? data : []);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", function(d2) {
+        return "list-item-photo-types list-item-" + d2;
+      });
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("photo_overlays.photo_type." + d2 + ".tooltip")).placement("top")
+        );
+      });
+      labelEnter.append("input").attr("type", "checkbox").on("change", function(d3_event, d2) {
+        context.photos().togglePhotoType(d2);
+      });
+      labelEnter.append("span").html(function(d2) {
+        return _t.html("photo_overlays.photo_type." + d2 + ".title");
+      });
+      li.merge(liEnter).classed("active", typeEnabled).selectAll("input").property("checked", typeEnabled);
+    }
+    function drawDateFilter(selection2) {
+      var data = context.photos().dateFilters();
+      function filterEnabled(d2) {
+        return context.photos().dateFilterValue(d2);
+      }
+      var ul = selection2.selectAll(".layer-list-date-filter").data([0]);
+      ul.exit().remove();
+      ul = ul.enter().append("ul").attr("class", "layer-list layer-list-date-filter").merge(ul);
+      var li = ul.selectAll(".list-item-date-filter").data(context.photos().shouldFilterByDate() ? data : []);
+      li.exit().remove();
+      var liEnter = li.enter().append("li").attr("class", "list-item-date-filter");
+      var labelEnter = liEnter.append("label").each(function(d2) {
+        select_default2(this).call(
+          uiTooltip().title(() => _t.append("photo_overlays.date_filter." + d2 + ".tooltip")).placement("top")
+        );
+      });
+      labelEnter.append("span").each(function(d2) {
+        _t.append("photo_overlays.date_filter." + d2 + ".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(d2) {
+        utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d2) || "");
+      }).on("change", function(d3_event, d2) {
+        var value = utilGetSetValue(select_default2(this)).trim();
+        context.photos().setDateFilter(d2, value, true);
+        li.selectAll("input").each(function(d4) {
+          utilGetSetValue(select_default2(this), context.photos().dateFilterValue(d4) || "");
+        });
+      });
+      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);
+      }
+    }
+    function drawLocalPhotos(selection2) {
+      var photoLayer = layers.layer("local-photos");
+      var hasData = photoLayer && photoLayer.hasData();
+      var showsData = hasData && photoLayer.enabled();
+      var ul = selection2.selectAll(".layer-list-local-photos").data(photoLayer ? [0] : []);
+      ul.exit().remove();
+      var ulEnter = ul.enter().append("ul").attr("class", "layer-list layer-list-local-photos");
+      var localPhotosEnter = ulEnter.append("li").attr("class", "list-item-local-photos");
+      var localPhotosLabelEnter = localPhotosEnter.append("label").call(uiTooltip().title(() => _t.append("local_photos.tooltip")));
+      localPhotosLabelEnter.append("input").attr("type", "checkbox").on("change", function() {
+        toggleLayer("local-photos");
+      });
+      localPhotosLabelEnter.call(_t.append("local_photos.header"));
+      localPhotosEnter.append("button").attr("class", "open-data-options").call(
+        uiTooltip().title(() => _t.append("local_photos.tooltip_edit")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        editLocalPhotos();
+      }).call(svgIcon("#iD-icon-more"));
+      localPhotosEnter.append("button").attr("class", "zoom-to-data").call(
+        uiTooltip().title(() => _t.append("local_photos.zoom")).placement(_mainLocalizer.textDirection() === "rtl" ? "right" : "left")
+      ).on("click", function(d3_event) {
+        if (select_default2(this).classed("disabled")) return;
+        d3_event.preventDefault();
+        d3_event.stopPropagation();
+        photoLayer.fitZoom();
+      }).call(svgIcon("#iD-icon-framed-dot", "monochrome"));
+      ul = ul.merge(ulEnter);
+      ul.selectAll(".list-item-local-photos").classed("active", showsData).selectAll("label").classed("deemphasize", !hasData).selectAll("input").property("disabled", !hasData).property("checked", showsData);
+      ul.selectAll("button.zoom-to-data").classed("disabled", !hasData);
+    }
+    function editLocalPhotos() {
+      context.container().call(settingsLocalPhotos);
+    }
+    function localPhotosChanged(d2) {
+      var localPhotosLayer = layers.layer("local-photos");
+      localPhotosLayer.fileList(d2);
+    }
+    context.layers().on("change.uiSectionPhotoOverlays", section.reRender);
+    context.photos().on("change.uiSectionPhotoOverlays", section.reRender);
+    context.map().on(
+      "move.photo_overlays",
+      debounce_default(function() {
+        window.requestIdleCallback(section.reRender);
+      }, 1e3)
+    );
+    return section;
+  }
+
+  // modules/ui/panes/map_data.js
+  function uiPaneMapData(context) {
+    var mapDataPane = uiPane("map-data", context).key(_t("map_data.key")).label(_t.append("map_data.title")).description(_t.append("map_data.description")).iconName("iD-icon-data").sections([
+      uiSectionDataLayers(context),
+      uiSectionPhotoOverlays(context),
+      uiSectionMapStyleOptions(context),
+      uiSectionMapFeatures(context)
+    ]);
+    return mapDataPane;
+  }
+
+  // modules/ui/panes/preferences.js
+  function uiPanePreferences(context) {
+    let preferencesPane = uiPane("preferences", context).key(_t("preferences.key")).label(_t.append("preferences.title")).description(_t.append("preferences.description")).iconName("fas-user-cog").sections([
+      uiSectionPrivacy(context)
+    ]);
+    return preferencesPane;
+  }
+
+  // modules/ui/init.js
+  function uiInit(context) {
+    var _initCounter = 0;
+    var _needWidth = {};
+    var _lastPointerType;
+    function render(container) {
+      container.on("click.ui", function(d3_event) {
+        if (d3_event.button !== 0) return;
+        if (!d3_event.composedPath) return;
+        var isOkayTarget = d3_event.composedPath().some(function(node) {
+          return node.nodeType === 1 && // clicking <input> focuses it and/or changes a value
+          (node.nodeName === "INPUT" || // clicking <label> affects its <input> by default
+          node.nodeName === "LABEL" || // clicking <a> opens a hyperlink by default
+          node.nodeName === "A");
+        });
+        if (isOkayTarget) return;
+        d3_event.preventDefault();
+      });
+      var detected = utilDetect();
+      if ("GestureEvent" in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
+      // but we only need to do this on desktop Safari anyway. – #7694
+      !detected.isMobileWebKit) {
+        container.on("gesturestart.ui gesturechange.ui gestureend.ui", function(d3_event) {
+          d3_event.preventDefault();
+        });
+      }
+      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(d2) {
+        return function(d3_event) {
+          if (d3_event.shiftKey) return;
+          if (context.container().select(".combobox").size()) return;
+          d3_event.preventDefault();
+          context.map().pan(d2, 100);
+        };
+      }
+    }
+    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(operation2) {
+        if (operation2.point) operation2.point(anchorPoint);
+      });
+      _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations);
+      context.map().supersurface.call(_editMenu);
+    };
+    ui.closeEditMenu = function() {
+      context.map().supersurface.select(".edit-menu").remove();
+    };
+    var _saveLoading = select_default2(null);
+    context.uploader().on("saveStarted.ui", function() {
+      _saveLoading = uiLoading(context).message(_t.html("save.uploading")).blocking(true);
+      context.container().call(_saveLoading);
+    }).on("saveEnded.ui", function() {
+      _saveLoading.close();
+      _saveLoading = select_default2(null);
+    });
+    marked.use({
+      mangle: false,
+      headerIds: false
+    });
+    return ui;
+  }
+
+  // modules/ui/commit_warnings.js
+  function uiCommitWarnings(context) {
+    function commitWarnings(selection2) {
+      var issuesBySeverity = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeDisabledRules: true });
+      for (var severity in issuesBySeverity) {
+        var issues = issuesBySeverity[severity];
+        if (severity !== "error") {
+          issues = issues.filter(function(issue) {
+            return issue.type !== "help_request";
+          });
+        }
+        var section = severity + "-section";
+        var issueItem = severity + "-item";
+        var container = selection2.selectAll("." + section).data(issues.length ? [0] : []);
+        container.exit().remove();
+        var containerEnter = container.enter().append("div").attr("class", "modal-section " + section + " fillL2");
+        containerEnter.append("h3").call(severity === "warning" ? _t.append("commit.warnings") : _t.append("commit.errors"));
+        containerEnter.append("ul").attr("class", "changeset-list");
+        container = containerEnter.merge(container);
+        var items = container.select("ul").selectAll("li").data(issues, function(d2) {
+          return d2.key;
+        });
+        items.exit().remove();
+        var itemsEnter = items.enter().append("li").attr("class", issueItem);
+        var buttons = itemsEnter.append("button").on("mouseover", function(d3_event, d2) {
+          if (d2.entityIds) {
+            context.surface().selectAll(
+              utilEntityOrMemberSelector(
+                d2.entityIds,
+                context.graph()
+              )
+            ).classed("hover", true);
+          }
+        }).on("mouseout", function() {
+          context.surface().selectAll(".hover").classed("hover", false);
+        }).on("click", function(d3_event, d2) {
+          context.validator().focusIssue(d2);
+        });
+        buttons.call(svgIcon("#iD-icon-alert", "pre-text"));
+        buttons.append("strong").attr("class", "issue-message");
+        buttons.filter(function(d2) {
+          return d2.tooltip;
+        }).call(
+          uiTooltip().title(function(d2) {
+            return d2.tooltip;
+          }).placement("top")
+        );
+        items = itemsEnter.merge(items);
+        items.selectAll(".issue-message").text("").each(function(d2) {
+          return d2.message(context)(select_default2(this));
+        });
+      }
+    }
+    return commitWarnings;
+  }
+
+  // modules/ui/lasso.js
+  function uiLasso(context) {
+    var group, polygon2;
+    lasso.coordinates = [];
+    function lasso(selection2) {
+      context.container().classed("lasso", true);
+      group = selection2.append("g").attr("class", "lasso hide");
+      polygon2 = group.append("path").attr("class", "lasso-path");
+      group.call(uiToggle(true));
+    }
+    function draw() {
+      if (polygon2) {
+        polygon2.data([lasso.coordinates]).attr("d", function(d2) {
+          return "M" + d2.join(" L") + " Z";
+        });
+      }
+    }
+    lasso.extent = function() {
+      return lasso.coordinates.reduce(function(extent, point) {
+        return extent.extend(geoExtent(point));
+      }, geoExtent());
+    };
+    lasso.p = function(_2) {
+      if (!arguments.length) return lasso;
+      lasso.coordinates.push(_2);
+      draw();
+      return lasso;
+    };
+    lasso.close = function() {
+      if (group) {
+        group.call(uiToggle(false, function() {
+          select_default2(this).remove();
+        }));
+      }
+      context.container().classed("lasso", false);
+    };
+    return lasso;
+  }
+
+  // node_modules/osm-community-index/lib/simplify.js
+  var import_diacritics2 = __toESM(require_diacritics(), 1);
+  function simplify(str) {
+    if (typeof str !== "string") return "";
+    return import_diacritics2.default.remove(
+      str.replace(/&/g, "and").replace(/(İ|i̇)/ig, "i").replace(/[\s\-=_!"#%'*{},.\/:;?\(\)\[\]@\\$\^*+<>«»~`’\u00a1\u00a7\u00b6\u00b7\u00bf\u037e\u0387\u055a-\u055f\u0589\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0af0\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f14\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1360-\u1368\u166d\u166e\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u1805\u1807-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cc0-\u1cc7\u1cd3\u2000-\u206f\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e7f\u3001-\u3003\u303d\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uaaf0\uaaf1\uabeb\ufe10-\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49-\ufe4c\ufe50-\ufe52\ufe54-\ufe57\ufe5f-\ufe61\ufe68\ufe6a\ufe6b\ufeff\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, "").toLowerCase()
+    );
+  }
+
+  // node_modules/osm-community-index/lib/resolve_strings.js
+  function resolveStrings(item, defaults, localizerFn) {
+    let itemStrings = Object.assign({}, item.strings);
+    let defaultStrings = Object.assign({}, defaults[item.type]);
+    const anyToken = new RegExp(/(\{\w+\})/, "gi");
+    if (localizerFn) {
+      if (itemStrings.community) {
+        const communityID = simplify(itemStrings.community);
+        itemStrings.community = localizerFn("_communities.".concat(communityID));
+      }
+      ["name", "description", "extendedDescription"].forEach((prop) => {
+        if (defaultStrings[prop]) defaultStrings[prop] = localizerFn("_defaults.".concat(item.type, ".").concat(prop));
+        if (itemStrings[prop]) itemStrings[prop] = localizerFn("".concat(item.id, ".").concat(prop));
+      });
+    }
+    let replacements = {
+      account: item.account,
+      community: itemStrings.community,
+      signupUrl: itemStrings.signupUrl,
+      url: itemStrings.url
+    };
+    if (!replacements.signupUrl) {
+      replacements.signupUrl = resolve(itemStrings.signupUrl || defaultStrings.signupUrl);
+    }
+    if (!replacements.url) {
+      replacements.url = resolve(itemStrings.url || defaultStrings.url);
+    }
+    let resolved = {
+      name: resolve(itemStrings.name || defaultStrings.name),
+      url: resolve(itemStrings.url || defaultStrings.url),
+      signupUrl: resolve(itemStrings.signupUrl || defaultStrings.signupUrl),
+      description: resolve(itemStrings.description || defaultStrings.description),
+      extendedDescription: resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription)
+    };
+    resolved.nameHTML = linkify(resolved.url, resolved.name);
+    resolved.urlHTML = linkify(resolved.url);
+    resolved.signupUrlHTML = linkify(resolved.signupUrl);
+    resolved.descriptionHTML = resolve(itemStrings.description || defaultStrings.description, true);
+    resolved.extendedDescriptionHTML = resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription, true);
+    return resolved;
+    function resolve(s2, addLinks) {
+      if (!s2) return void 0;
+      let result = s2;
+      for (let key in replacements) {
+        const token = "{".concat(key, "}");
+        const regex = new RegExp(token, "g");
+        if (regex.test(result)) {
+          let replacement = replacements[key];
+          if (!replacement) {
+            throw new Error("Cannot resolve token: ".concat(token));
+          } else {
+            if (addLinks && (key === "signupUrl" || key === "url")) {
+              replacement = linkify(replacement);
+            }
+            result = result.replace(regex, replacement);
+          }
+        }
+      }
+      const leftovers = result.match(anyToken);
+      if (leftovers) {
+        throw new Error("Cannot resolve tokens: ".concat(leftovers));
+      }
+      if (addLinks && item.type === "reddit") {
+        result = result.replace(/(\/r\/\w+\/*)/i, (match) => linkify(resolved.url, match));
+      }
+      return result;
+    }
+    function linkify(url, text) {
+      if (!url) return void 0;
+      text = text || url;
+      return '<a target="_blank" href="'.concat(url, '">').concat(text, "</a>");
+    }
+  }
+
+  // modules/ui/success.js
+  var _oci = null;
+  function uiSuccess(context) {
+    const MAXEVENTS = 2;
+    const dispatch14 = dispatch_default("cancel");
+    let _changeset2;
+    let _location;
+    ensureOSMCommunityIndex();
+    function ensureOSMCommunityIndex() {
+      const data = _mainFileFetcher;
+      return Promise.all([
+        data.get("oci_features"),
+        data.get("oci_resources"),
+        data.get("oci_defaults")
+      ]).then((vals) => {
+        if (_oci) return _oci;
+        if (vals[0] && Array.isArray(vals[0].features)) {
+          _sharedLocationManager.mergeCustomGeoJSON(vals[0]);
+        }
+        let ociResources = Object.values(vals[1].resources);
+        if (ociResources.length) {
+          return _sharedLocationManager.mergeLocationSets(ociResources).then(() => {
+            _oci = {
+              resources: ociResources,
+              defaults: vals[2].defaults
+            };
+            return _oci;
+          });
+        } else {
+          _oci = {
+            resources: [],
+            // no resources?
+            defaults: vals[2].defaults
+          };
+          return _oci;
+        }
+      });
+    }
+    function parseEventDate(when) {
+      if (!when) return;
+      let raw = when.trim();
+      if (!raw) return;
+      if (!/Z$/.test(raw)) {
+        raw += "Z";
+      }
+      const parsed = new Date(raw);
+      return new Date(parsed.toUTCString().slice(0, 25));
+    }
+    function success(selection2) {
+      let header = selection2.append("div").attr("class", "header fillL");
+      header.append("h2").call(_t.append("success.just_edited"));
+      header.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", () => dispatch14.call("cancel")).call(svgIcon("#iD-icon-close"));
+      let body = selection2.append("div").attr("class", "body save-success fillL");
+      let summary = body.append("div").attr("class", "save-summary");
+      summary.append("h3").call(_t.append("success.thank_you" + (_location ? "_location" : ""), { where: _location }));
+      summary.append("p").call(_t.append("success.help_html")).append("a").attr("class", "link-out").attr("target", "_blank").attr("href", _t("success.help_link_url")).call(svgIcon("#iD-icon-out-link", "inline")).append("span").call(_t.append("success.help_link_text"));
+      let osm = context.connection();
+      if (!osm) return;
+      let changesetURL = osm.changesetURL(_changeset2.id);
+      let table = summary.append("table").attr("class", "summary-table");
+      let row = table.append("tr").attr("class", "summary-row");
+      row.append("td").attr("class", "cell-icon summary-icon").append("a").attr("target", "_blank").attr("href", changesetURL).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", "#iD-logo-osm");
+      let summaryDetail = row.append("td").attr("class", "cell-detail summary-detail");
+      summaryDetail.append("a").attr("class", "cell-detail summary-view-on-osm").attr("target", "_blank").attr("href", changesetURL).call(_t.append("success.view_on_osm"));
+      summaryDetail.append("div").html(_t.html("success.changeset_id", {
+        changeset_id: { html: '<a href="'.concat(changesetURL, '" target="_blank">').concat(_changeset2.id, "</a>") }
+      }));
+      if (showDonationMessage !== false) {
+        const donationUrl = "https://supporting.openstreetmap.org/";
+        let supporting = body.append("div").attr("class", "save-supporting");
+        supporting.append("h3").call(_t.append("success.supporting.title"));
+        supporting.append("p").call(_t.append("success.supporting.details"));
+        table = supporting.append("table").attr("class", "supporting-table");
+        row = table.append("tr").attr("class", "supporting-row");
+        row.append("td").attr("class", "cell-icon supporting-icon").append("a").attr("target", "_blank").attr("href", donationUrl).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", "#iD-donation");
+        let supportingDetail = row.append("td").attr("class", "cell-detail supporting-detail");
+        supportingDetail.append("a").attr("class", "cell-detail support-the-map").attr("target", "_blank").attr("href", donationUrl).call(_t.append("success.supporting.donation.title"));
+        supportingDetail.append("div").call(_t.append("success.supporting.donation.details"));
+      }
+      ensureOSMCommunityIndex().then((oci) => {
+        const loc = context.map().center();
+        const validHere = _sharedLocationManager.locationSetsAt(loc);
+        let communities = [];
+        oci.resources.forEach((resource) => {
+          let area = validHere[resource.locationSetID];
+          if (!area) return;
+          const localizer = (stringID) => _t.html("community.".concat(stringID));
+          resource.resolved = resolveStrings(resource, oci.defaults, localizer);
+          communities.push({
+            area,
+            order: resource.order || 0,
+            resource
+          });
+        });
+        communities.sort((a2, b2) => a2.area - b2.area || b2.order - a2.order);
+        body.call(showCommunityLinks, communities.map((c2) => c2.resource));
+      });
+    }
+    function showCommunityLinks(selection2, resources) {
+      let communityLinks = selection2.append("div").attr("class", "save-communityLinks");
+      communityLinks.append("h3").call(_t.append("success.like_osm"));
+      let table = communityLinks.append("table").attr("class", "community-table");
+      let row = table.selectAll(".community-row").data(resources);
+      let rowEnter = row.enter().append("tr").attr("class", "community-row");
+      rowEnter.append("td").attr("class", "cell-icon community-icon").append("a").attr("target", "_blank").attr("href", (d2) => d2.resolved.url).append("svg").attr("class", "logo-small").append("use").attr("xlink:href", (d2) => "#community-".concat(d2.type));
+      let communityDetail = rowEnter.append("td").attr("class", "cell-detail community-detail");
+      communityDetail.each(showCommunityDetails);
+      communityLinks.append("div").attr("class", "community-missing").call(_t.append("success.missing")).append("a").attr("class", "link-out").attr("target", "_blank").call(svgIcon("#iD-icon-out-link", "inline")).attr("href", "https://github.com/osmlab/osm-community-index/issues").append("span").call(_t.append("success.tell_us"));
+    }
+    function showCommunityDetails(d2) {
+      let selection2 = select_default2(this);
+      let communityID = d2.id;
+      selection2.append("div").attr("class", "community-name").html(d2.resolved.nameHTML);
+      selection2.append("div").attr("class", "community-description").html(d2.resolved.descriptionHTML);
+      if (d2.resolved.extendedDescriptionHTML || d2.languageCodes && d2.languageCodes.length) {
+        selection2.append("div").call(
+          uiDisclosure(context, "community-more-".concat(d2.id), false).expanded(false).updatePreference(false).label(() => _t.append("success.more")).content(showMore)
+        );
+      }
+      let nextEvents = (d2.events || []).map((event) => {
+        event.date = parseEventDate(event.when);
+        return event;
+      }).filter((event) => {
+        const t2 = event.date.getTime();
+        const now3 = (/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0);
+        return !isNaN(t2) && t2 >= now3;
+      }).sort((a2, b2) => {
+        return a2.date < b2.date ? -1 : a2.date > b2.date ? 1 : 0;
+      }).slice(0, MAXEVENTS);
+      if (nextEvents.length) {
+        selection2.append("div").call(
+          uiDisclosure(context, "community-events-".concat(d2.id), false).expanded(false).updatePreference(false).label(_t.html("success.events")).content(showNextEvents)
+        ).select(".hide-toggle").append("span").attr("class", "badge-text").text(nextEvents.length);
+      }
+      function showMore(selection3) {
+        let more = selection3.selectAll(".community-more").data([0]);
+        let moreEnter = more.enter().append("div").attr("class", "community-more");
+        if (d2.resolved.extendedDescriptionHTML) {
+          moreEnter.append("div").attr("class", "community-extended-description").html(d2.resolved.extendedDescriptionHTML);
+        }
+        if (d2.languageCodes && d2.languageCodes.length) {
+          const languageList = d2.languageCodes.map((code) => _mainLocalizer.languageName(code)).join(", ");
+          moreEnter.append("div").attr("class", "community-languages").call(_t.append("success.languages", { languages: languageList }));
+        }
+      }
+      function showNextEvents(selection3) {
+        let events = selection3.append("div").attr("class", "community-events");
+        let item = events.selectAll(".community-event").data(nextEvents);
+        let itemEnter = item.enter().append("div").attr("class", "community-event");
+        itemEnter.append("div").attr("class", "community-event-name").append("a").attr("target", "_blank").attr("href", (d4) => d4.url).text((d4) => {
+          let name = d4.name;
+          if (d4.i18n && d4.id) {
+            name = _t("community.".concat(communityID, ".events.").concat(d4.id, ".name"), { default: name });
+          }
+          return name;
+        });
+        itemEnter.append("div").attr("class", "community-event-when").text((d4) => {
+          let options2 = { weekday: "short", day: "numeric", month: "short", year: "numeric" };
+          if (d4.date.getHours() || d4.date.getMinutes()) {
+            options2.hour = "numeric";
+            options2.minute = "numeric";
+          }
+          return d4.date.toLocaleString(_mainLocalizer.localeCode(), options2);
+        });
+        itemEnter.append("div").attr("class", "community-event-where").text((d4) => {
+          let where = d4.where;
+          if (d4.i18n && d4.id) {
+            where = _t("community.".concat(communityID, ".events.").concat(d4.id, ".where"), { default: where });
+          }
+          return where;
+        });
+        itemEnter.append("div").attr("class", "community-event-description").text((d4) => {
+          let description = d4.description;
+          if (d4.i18n && d4.id) {
+            description = _t("community.".concat(communityID, ".events.").concat(d4.id, ".description"), { default: description });
+          }
+          return description;
+        });
+      }
+    }
+    success.changeset = function(val) {
+      if (!arguments.length) return _changeset2;
+      _changeset2 = val;
+      return success;
+    };
+    success.location = function(val) {
+      if (!arguments.length) return _location;
+      _location = val;
+      return success;
+    };
+    return utilRebind(success, dispatch14, "on");
+  }
+
+  // modules/ui/fields/input.js
+  var likelyRawNumberFormat = /^-?(0\.\d*|\d*\.\d{0,2}(\d{4,})?|\d{4,}\.\d{3})$/;
+  function uiFieldText(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var input = select_default2(null);
+    var outlinkButton = select_default2(null);
+    var wrap2 = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
+    var _entityIDs = [];
+    var _tags;
+    var _phoneFormats = {};
+    const isDirectionField = field.key.split(":").some((keyPart) => keyPart === "direction");
+    const formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
+    const parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
+    const countDecimalPlaces = _mainLocalizer.decimalPlaceCounter(_mainLocalizer.languageCode());
+    if (field.type === "tel") {
+      _mainFileFetcher.get("phone_formats").then(function(d2) {
+        _phoneFormats = d2;
+        updatePhonePlaceholder();
+      }).catch(function() {
+      });
+    }
+    function calcLocked() {
+      var isLocked = (field.id === "brand" || field.id === "network" || field.id === "operator" || field.id === "flag") && _entityIDs.length && _entityIDs.some(function(entityID) {
+        var entity = context.graph().hasEntity(entityID);
+        if (!entity) return false;
+        if (entity.tags.wikidata) return true;
+        var preset = _mainPresetIndex.match(entity, context.graph());
+        var isSuggestion = preset && preset.suggestion;
+        var which = field.id;
+        return isSuggestion && !!entity.tags[which] && !!entity.tags[which + ":wikidata"];
+      });
+      field.locked(isLocked);
+    }
+    function i3(selection2) {
+      calcLocked();
+      var isLocked = field.locked();
+      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      input = wrap2.selectAll("input").data([0]);
+      input = input.enter().append("input").attr("type", field.type === "identifier" ? "text" : field.type).attr("id", field.domId).classed(field.type, true).call(utilNoAuto).merge(input);
+      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
+      wrap2.call(_lengthIndicator);
+      if (field.type === "tel") {
+        updatePhonePlaceholder();
+      } else if (field.type === "number") {
+        var rtl = _mainLocalizer.textDirection() === "rtl";
+        input.attr("type", "text");
+        var inc = field.increment;
+        var buttons = wrap2.selectAll(".increment, .decrement").data(rtl ? [inc, -inc] : [-inc, inc]);
+        buttons.enter().append("button").attr("class", function(d2) {
+          var which = d2 > 0 ? "increment" : "decrement";
+          return "form-field-button " + which;
+        }).attr("title", function(d2) {
+          var which = d2 > 0 ? "increment" : "decrement";
+          return _t("inspector.".concat(which));
+        }).merge(buttons).on("click", function(d3_event, d2) {
+          d3_event.preventDefault();
+          var isMixed = Array.isArray(_tags[field.key]);
+          if (isMixed) return;
+          var raw_vals = input.node().value || "0";
+          var vals = raw_vals.split(";");
+          vals = vals.map(function(v2) {
+            v2 = v2.trim();
+            const isRawNumber = likelyRawNumberFormat.test(v2);
+            var num = isRawNumber ? parseFloat(v2) : parseLocaleFloat(v2);
+            if (isDirectionField) {
+              const compassDir = cardinal[v2.toLowerCase()];
+              if (compassDir !== void 0) {
+                num = compassDir;
+              }
+            }
+            if (!isFinite(num)) return v2;
+            num = parseFloat(num);
+            if (!isFinite(num)) return v2;
+            num += d2;
+            if (isDirectionField) {
+              num = (num % 360 + 360) % 360;
+            }
+            return formatFloat(clamped(num), isRawNumber ? v2.includes(".") ? v2.split(".")[1].length : 0 : countDecimalPlaces(v2));
+          });
+          input.node().value = vals.join(";");
+          change()();
+        });
+      } else if (field.type === "identifier" && field.urlFormat && field.pattern) {
+        input.attr("type", "text");
+        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
+        outlinkButton = outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", function() {
+          var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
+          if (domainResults.length >= 2 && domainResults[1]) {
+            var domain = domainResults[1];
+            return _t("icons.view_on", { domain });
+          }
+          return "";
+        }).merge(outlinkButton);
+        outlinkButton.on("click", function(d3_event) {
+          d3_event.preventDefault();
+          var value = validIdentifierValueForLink();
+          if (value) {
+            var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
+            window.open(url, "_blank");
+          }
+        }).classed("disabled", () => !validIdentifierValueForLink()).merge(outlinkButton);
+      } else if (field.type === "url") {
+        input.attr("type", "text");
+        outlinkButton = wrap2.selectAll(".foreign-id-permalink").data([0]);
+        outlinkButton.enter().append("button").call(svgIcon("#iD-icon-out-link")).attr("class", "form-field-button foreign-id-permalink").attr("title", () => _t("icons.visit_website")).on("click", function(d3_event) {
+          d3_event.preventDefault();
+          const value = validIdentifierValueForLink();
+          if (value) window.open(value, "_blank");
+        }).merge(outlinkButton);
+      } else if (field.type === "colour") {
+        input.attr("type", "text");
+        updateColourPreview();
+      } else if (field.type === "date") {
+        input.attr("type", "text");
+        updateDateField();
+      }
+    }
+    function updateColourPreview() {
+      wrap2.selectAll(".colour-preview").remove();
+      const colour = utilGetSetValue(input);
+      if (!isColourValid(colour) && colour !== "") {
+        wrap2.selectAll("input.colour-selector").remove();
+        wrap2.selectAll(".form-field-button").remove();
+        return;
+      }
+      var colourSelector = wrap2.selectAll(".colour-selector").data([0]);
+      colourSelector.enter().append("input").attr("type", "color").attr("class", "colour-selector").on("input", debounce_default(function(d3_event) {
+        d3_event.preventDefault();
+        var colour2 = this.value;
+        if (!isColourValid(colour2)) return;
+        utilGetSetValue(input, this.value);
+        change()();
+        updateColourPreview();
+      }, 100));
+      wrap2.selectAll("input.colour-selector").attr("value", colour);
+      var chooserButton = wrap2.selectAll(".colour-preview").data([colour]);
+      chooserButton = chooserButton.enter().append("div").attr("class", "form-field-button colour-preview").append("div").style("background-color", (d2) => d2).attr("class", "colour-box");
+      if (colour === "") {
+        chooserButton = chooserButton.call(svgIcon("#iD-icon-edit"));
+      }
+      chooserButton.on("click", () => wrap2.select(".colour-selector").node().showPicker());
+    }
+    function updateDateField() {
+      function isDateValid(date2) {
+        return date2.match(/^[0-9]{4}(-[0-9]{2}(-[0-9]{2})?)?$/);
+      }
+      const date = utilGetSetValue(input);
+      const now3 = /* @__PURE__ */ new Date();
+      const today = new Date(now3.getTime() - now3.getTimezoneOffset() * 6e4).toISOString().split("T")[0];
+      if ((field.key === "check_date" || field.key === "survey:date") && date !== today) {
+        wrap2.selectAll(".date-set-today").data([0]).enter().append("button").attr("class", "form-field-button date-set-today").call(svgIcon("#fas-rotate")).call(uiTooltip().title(() => _t.append("inspector.set_today"))).on("click", () => {
+          utilGetSetValue(input, today);
+          change()();
+          updateDateField();
+        });
+      } else {
+        wrap2.selectAll(".date-set-today").remove();
+      }
+      if (!isDateValid(date) && date !== "") {
+        wrap2.selectAll("input.date-selector").remove();
+        wrap2.selectAll(".date-calendar").remove();
+        return;
+      }
+      if (utilDetect().browser !== "Safari") {
+        var dateSelector = wrap2.selectAll(".date-selector").data([0]);
+        dateSelector.enter().append("input").attr("type", "date").attr("class", "date-selector").on("input", debounce_default(function(d3_event) {
+          d3_event.preventDefault();
+          var date2 = this.value;
+          if (!isDateValid(date2)) return;
+          utilGetSetValue(input, this.value);
+          change()();
+          updateDateField();
+        }, 100));
+        wrap2.selectAll("input.date-selector").attr("value", date);
+        var calendarButton = wrap2.selectAll(".date-calendar").data([date]);
+        calendarButton = calendarButton.enter().append("button").attr("class", "form-field-button date-calendar").call(svgIcon("#fas-calendar-days"));
+        calendarButton.on("click", () => wrap2.select(".date-selector").node().showPicker());
+      }
+    }
+    function updatePhonePlaceholder() {
+      if (input.empty() || !Object.keys(_phoneFormats).length) return;
+      var extent = combinedEntityExtent();
+      var countryCode = extent && iso1A2Code(extent.center());
+      var format2 = countryCode && _phoneFormats[countryCode.toLowerCase()];
+      if (format2) input.attr("placeholder", format2);
+    }
+    function validIdentifierValueForLink() {
+      var _a3;
+      const value = utilGetSetValue(input).trim();
+      if (field.type === "url" && value) {
+        try {
+          return new URL(value).href;
+        } catch {
+          return null;
+        }
+      }
+      if (field.type === "identifier" && field.pattern) {
+        return value && ((_a3 = value.match(new RegExp(field.pattern))) == null ? void 0 : _a3[0]);
+      }
+      return null;
+    }
+    function clamped(num) {
+      if (field.minValue !== void 0) {
+        num = Math.max(num, field.minValue);
+      }
+      if (field.maxValue !== void 0) {
+        num = Math.min(num, field.maxValue);
+      }
+      return num;
+    }
+    function getVals(tags) {
+      if (field.keys) {
+        const multiSelection = context.selectedIDs();
+        tags = multiSelection.length > 1 ? context.selectedIDs().map((id2) => context.graph().entity(id2)).map((entity) => entity.tags) : [tags];
+        return tags.map((tags2) => new Set(field.keys.reduce((acc, key) => acc.concat(tags2[key]), []).filter(Boolean))).map((vals) => vals.size === 0 ? /* @__PURE__ */ new Set([void 0]) : vals).reduce((a2, b2) => /* @__PURE__ */ new Set([...a2, ...b2]));
+      } else {
+        return new Set([].concat(tags[field.key]));
+      }
+    }
+    function change(onInput) {
+      return function() {
+        var t2 = {};
+        var val = utilGetSetValue(input);
+        if (!onInput) val = context.cleanTagValue(val);
+        if (!val && getVals(_tags).size > 1) return;
+        var displayVal = val;
+        if (field.type === "number" && val) {
+          var numbers2 = val.split(";");
+          numbers2 = numbers2.map(function(v2) {
+            if (likelyRawNumberFormat.test(v2)) {
+              return v2;
+            }
+            var num = parseLocaleFloat(v2);
+            const fractionDigits = countDecimalPlaces(v2);
+            return isFinite(num) ? clamped(num).toFixed(fractionDigits) : v2;
+          });
+          val = numbers2.join(";");
+        }
+        if (!onInput) utilGetSetValue(input, displayVal);
+        t2[field.key] = val || void 0;
+        if (field.keys) {
+          dispatch14.call("change", this, (tags) => {
+            if (field.keys.some((key) => tags[key])) {
+              field.keys.filter((key) => tags[key]).forEach((key) => {
+                tags[key] = val || void 0;
+              });
+            } else {
+              tags[field.key] = val || void 0;
+            }
+            return tags;
+          }, onInput);
+        } else {
+          dispatch14.call("change", this, t2, onInput);
+        }
+      };
+    }
+    i3.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return i3;
+    };
+    i3.tags = function(tags) {
+      var _a3;
+      _tags = tags;
+      const vals = getVals(tags);
+      const isMixed = vals.size > 1;
+      var val = vals.size === 1 ? (_a3 = [...vals][0]) != null ? _a3 : "" : "";
+      var shouldUpdate;
+      if (field.type === "number" && val) {
+        var numbers2 = val.split(";");
+        var oriNumbers = utilGetSetValue(input).split(";");
+        if (numbers2.length !== oriNumbers.length) shouldUpdate = true;
+        numbers2 = numbers2.map(function(v2) {
+          v2 = v2.trim();
+          var num = Number(v2);
+          if (!isFinite(num) || v2 === "") return v2;
+          const fractionDigits = v2.includes(".") ? v2.split(".")[1].length : 0;
+          return formatFloat(num, fractionDigits);
+        });
+        val = numbers2.join(";");
+        shouldUpdate = (inputValue, setValue) => {
+          const inputNums = inputValue.split(";").map(
+            (setVal) => likelyRawNumberFormat.test(setVal) ? parseFloat(setVal) : parseLocaleFloat(setVal)
+          );
+          const setNums = setValue.split(";").map(parseLocaleFloat);
+          return !isEqual_default(inputNums, setNums);
+        };
+      }
+      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]);
+      }
+    };
+    i3.focus = function() {
+      var node = input.node();
+      if (node) node.focus();
+    };
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    return utilRebind(i3, dispatch14, "on");
+  }
+
+  // modules/ui/fields/access.js
+  function uiFieldAccess(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var items = select_default2(null);
+    var _tags;
+    function access(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var list2 = wrap2.selectAll("ul").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
+      items = list2.selectAll("li").data(field.keys);
+      var enter = items.enter().append("li").attr("class", function(d2) {
+        return "labeled-input preset-access-" + d2;
+      });
+      enter.append("div").attr("class", "label preset-label-access").attr("for", function(d2) {
+        return "preset-input-access-" + d2;
+      }).html(function(d2) {
+        return field.t.html("types." + d2);
+      });
+      enter.append("div").attr("class", "preset-input-access-wrap").append("input").attr("type", "text").attr("class", function(d2) {
+        return "preset-input-access preset-input-access-" + d2;
+      }).call(utilNoAuto).each(function(d2) {
+        select_default2(this).call(
+          uiCombobox(context, "access-" + d2).data(access.options(d2))
+        );
+      });
+      items = items.merge(enter);
+      wrap2.selectAll(".preset-input-access").on("change", change).on("blur", change);
+    }
+    function change(d3_event, d2) {
+      var tag2 = {};
+      var value = context.cleanTagValue(utilGetSetValue(select_default2(this)));
+      if (!value && typeof _tags[d2] !== "string") return;
+      tag2[d2] = value || void 0;
+      dispatch14.call("change", this, tag2);
+    }
+    access.options = function(type2) {
+      var options2 = [
+        "yes",
+        "no",
+        "designated",
+        "permissive",
+        "destination",
+        "customers",
+        "private",
+        "permit",
+        "unknown"
+      ];
+      if (type2 === "access") {
+        options2 = options2.filter((v2) => v2 !== "yes" && v2 !== "designated");
+      }
+      if (type2 === "bicycle") {
+        options2.splice(options2.length - 4, 0, "dismount");
+      }
+      var stringsField = field.resolveReference("stringsCrossReference");
+      return options2.map(function(option) {
+        return {
+          title: stringsField.t("options." + option + ".description"),
+          value: option
+        };
+      });
+    };
+    const placeholdersByTag = {
+      highway: {
+        footway: {
+          foot: "designated",
+          motor_vehicle: "no"
+        },
+        steps: {
+          foot: "yes",
+          motor_vehicle: "no",
+          bicycle: "no",
+          horse: "no"
+        },
+        ladder: {
+          foot: "yes",
+          motor_vehicle: "no",
+          bicycle: "no",
+          horse: "no"
+        },
+        pedestrian: {
+          foot: "yes",
+          motor_vehicle: "no"
+        },
+        cycleway: {
+          motor_vehicle: "no",
+          bicycle: "designated"
+        },
+        bridleway: {
+          motor_vehicle: "no",
+          horse: "designated"
+        },
+        path: {
+          foot: "yes",
+          motor_vehicle: "no",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        motorway: {
+          foot: "no",
+          motor_vehicle: "yes",
+          bicycle: "no",
+          horse: "no"
+        },
+        trunk: {
+          motor_vehicle: "yes"
+        },
+        primary: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        secondary: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        tertiary: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        residential: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        unclassified: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        service: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        motorway_link: {
+          foot: "no",
+          motor_vehicle: "yes",
+          bicycle: "no",
+          horse: "no"
+        },
+        trunk_link: {
+          motor_vehicle: "yes"
+        },
+        primary_link: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        secondary_link: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        tertiary_link: {
+          foot: "yes",
+          motor_vehicle: "yes",
+          bicycle: "yes",
+          horse: "yes"
+        },
+        construction: {
+          access: "no"
+        },
+        busway: {
+          access: "no",
+          bus: "designated",
+          emergency: "yes"
+        }
+      },
+      barrier: {
+        bollard: {
+          access: "no",
+          bicycle: "yes",
+          foot: "yes"
+        },
+        bus_trap: {
+          motor_vehicle: "no",
+          psv: "yes",
+          foot: "yes",
+          bicycle: "yes"
+        },
+        city_wall: {
+          access: "no"
+        },
+        coupure: {
+          access: "yes"
+        },
+        cycle_barrier: {
+          motor_vehicle: "no"
+        },
+        ditch: {
+          access: "no"
+        },
+        entrance: {
+          access: "yes"
+        },
+        fence: {
+          access: "no"
+        },
+        hedge: {
+          access: "no"
+        },
+        jersey_barrier: {
+          access: "no"
+        },
+        motorcycle_barrier: {
+          motor_vehicle: "no"
+        },
+        rail_guard: {
+          access: "no"
+        }
+      }
+    };
+    access.tags = function(tags) {
+      _tags = tags;
+      utilGetSetValue(items.selectAll(".preset-input-access"), function(d2) {
+        return typeof tags[d2] === "string" ? tags[d2] : "";
+      }).classed("mixed", function(d2) {
+        return tags[d2] && Array.isArray(tags[d2]);
+      }).attr("title", function(d2) {
+        return tags[d2] && Array.isArray(tags[d2]) && tags[d2].filter(Boolean).join("\n");
+      }).attr("placeholder", function(d2) {
+        if (tags[d2] && Array.isArray(tags[d2])) {
+          return _t("inspector.multiple_values");
+        }
+        if (d2 === "bicycle" || d2 === "motor_vehicle") {
+          if (tags.vehicle && typeof tags.vehicle === "string") {
+            return tags.vehicle;
+          }
+        }
+        if (tags.access && typeof tags.access === "string") {
+          return tags.access;
+        }
+        function getPlaceholdersByTag(key, placeholdersByKey) {
+          if (typeof tags[key] === "string") {
+            if (placeholdersByKey[tags[key]] && placeholdersByKey[tags[key]][d2]) {
+              return placeholdersByKey[tags[key]][d2];
+            }
+          } else {
+            var impliedAccesses = tags[key].filter(Boolean).map(function(val) {
+              return placeholdersByKey[val] && placeholdersByKey[val][d2];
+            }).filter(Boolean);
+            if (impliedAccesses.length === tags[key].length && new Set(impliedAccesses).size === 1) {
+              return impliedAccesses[0];
+            }
+          }
+        }
+        for (const key in placeholdersByTag) {
+          if (tags[key]) {
+            const impliedAccess = getPlaceholdersByTag(key, placeholdersByTag[key]);
+            if (impliedAccess) {
+              return impliedAccess;
+            }
+          }
+        }
+        if (d2 === "access" && !tags.barrier) {
+          return "yes";
+        }
+        return field.placeholder();
+      });
+    };
+    access.focus = function() {
+      items.selectAll(".preset-input-access").node().focus();
+    };
+    return utilRebind(access, dispatch14, "on");
+  }
+
+  // modules/ui/fields/address.js
+  function uiFieldAddress(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var _selection = select_default2(null);
+    var _wrap = select_default2(null);
+    var addrField = _mainPresetIndex.field("address");
+    var _entityIDs = [];
+    var _tags;
+    var _countryCode;
+    var _addressFormats = [{
+      format: [
+        ["housenumber", "street"],
+        ["city", "postcode"]
+      ]
+    }];
+    _mainFileFetcher.get("address_formats").then(function(d2) {
+      _addressFormats = d2;
+      if (!_selection.empty()) {
+        _selection.call(address);
+      }
+    }).catch(function() {
+    });
+    function getNear(isAddressable, type2, searchRadius, resultProp) {
+      var extent = combinedEntityExtent();
+      var l2 = extent.center();
+      var box = geoExtent(l2).padByMeters(searchRadius);
+      var features = context.history().intersects(box).filter(isAddressable).map((d2) => {
+        let dist = geoSphericalDistance(d2.extent(context.graph()).center(), l2);
+        if (d2.geometry(context.graph()) === "line") {
+          var loc = context.projection([
+            (extent[0][0] + extent[1][0]) / 2,
+            (extent[0][1] + extent[1][1]) / 2
+          ]);
+          var choice = geoChooseEdge(context.graph().childNodes(d2), loc, context.projection);
+          dist = geoSphericalDistance(choice.loc, l2);
+        }
+        const value = resultProp && d2.tags[resultProp] ? d2.tags[resultProp] : d2.tags.name;
+        let title = value;
+        if (type2 === "street") {
+          title = "".concat(addrField.t("placeholders.street"), ": ").concat(title);
+        } else if (type2 === "place") {
+          title = "".concat(addrField.t("placeholders.place"), ": ").concat(title);
+        }
+        return {
+          title,
+          value,
+          dist,
+          type: type2,
+          klass: "address-".concat(type2)
+        };
+      }).sort(function(a2, b2) {
+        return a2.dist - b2.dist;
+      });
+      return utilArrayUniqBy(features, "value");
+    }
+    function getNearStreets() {
+      function isAddressable(d2) {
+        return d2.tags.highway && d2.tags.name && d2.type === "way";
+      }
+      return getNear(isAddressable, "street", 200);
+    }
+    function getNearPlaces() {
+      function isAddressable(d2) {
+        if (d2.tags.name) {
+          if (d2.tags.place) return true;
+          if (d2.tags.boundary === "administrative" && d2.tags.admin_level > 8) return true;
+        }
+        return false;
+      }
+      return getNear(isAddressable, "place", 200);
+    }
+    function getNearCities() {
+      function isAddressable(d2) {
+        if (d2.tags.name) {
+          if (d2.tags.boundary === "administrative" && d2.tags.admin_level === "8") return true;
+          if (d2.tags.border_type === "city") return true;
+          if (d2.tags.place === "city" || d2.tags.place === "town" || d2.tags.place === "village") return true;
+        }
+        if (d2.tags["".concat(field.key, ":city")]) return true;
+        return false;
+      }
+      return getNear(isAddressable, "city", 200, "".concat(field.key, ":city"));
+    }
+    function getNearPostcodes() {
+      return [...new Set([].concat(getNearValues("postcode")).concat(getNear((d2) => d2.tags.postal_code, "postcode", 200, "postal_code")))];
+    }
+    function getNearValues(key) {
+      const tagKey = "".concat(field.key, ":").concat(key);
+      function hasTag(d2) {
+        return _entityIDs.indexOf(d2.id) === -1 && d2.tags[tagKey];
+      }
+      return getNear(hasTag, key, 200, tagKey);
+    }
+    function updateForCountryCode() {
+      if (!_countryCode) return;
+      var addressFormat;
+      for (var i3 = 0; i3 < _addressFormats.length; i3++) {
+        var format2 = _addressFormats[i3];
+        if (!format2.countryCodes) {
+          addressFormat = format2;
+        } else if (format2.countryCodes.indexOf(_countryCode) !== -1) {
+          addressFormat = format2;
+          break;
+        }
+      }
+      var dropdowns = addressFormat.dropdowns || [
+        "city",
+        "county",
+        "country",
+        "district",
+        "hamlet",
+        "neighbourhood",
+        "place",
+        "postcode",
+        "province",
+        "quarter",
+        "state",
+        "street",
+        "street+place",
+        "subdistrict",
+        "suburb"
+      ];
+      var widths = addressFormat.widths || {
+        housenumber: 1 / 5,
+        unit: 1 / 5,
+        street: 1 / 2,
+        place: 1 / 2,
+        city: 2 / 3,
+        state: 1 / 4,
+        postcode: 1 / 3
+      };
+      function row(r2) {
+        var total = r2.reduce(function(sum, key) {
+          return sum + (widths[key] || 0.5);
+        }, 0);
+        return r2.map(function(key) {
+          return {
+            id: key,
+            width: (widths[key] || 0.5) / total
+          };
+        });
+      }
+      var rows = _wrap.selectAll(".addr-row").data(addressFormat.format, function(d2) {
+        return d2.toString();
+      });
+      rows.exit().remove();
+      rows.enter().append("div").attr("class", "addr-row").selectAll("input").data(row).enter().append("input").property("type", "text").call(updatePlaceholder).attr("class", function(d2) {
+        return "addr-" + d2.id;
+      }).call(utilNoAuto).each(addDropdown).style("width", function(d2) {
+        return d2.width * 100 + "%";
+      });
+      function addDropdown(d2) {
+        if (dropdowns.indexOf(d2.id) === -1) return;
+        var nearValues;
+        switch (d2.id) {
+          case "street":
+            nearValues = getNearStreets;
+            break;
+          case "place":
+            nearValues = getNearPlaces;
+            break;
+          case "street+place":
+            nearValues = () => [].concat(getNearStreets()).concat(getNearPlaces());
+            d2.isAutoStreetPlace = true;
+            d2.id = _tags["".concat(field.key, ":place")] ? "place" : "street";
+            break;
+          case "city":
+            nearValues = getNearCities;
+            break;
+          case "postcode":
+            nearValues = getNearPostcodes;
+            break;
+          default:
+            nearValues = getNearValues;
+        }
+        select_default2(this).call(
+          uiCombobox(context, "address-".concat(d2.isAutoStreetPlace ? "street-place" : d2.id)).minItems(1).caseSensitive(true).fetcher(function(typedValue, callback) {
+            typedValue = typedValue.toLowerCase();
+            callback(nearValues(d2.id).filter((v2) => v2.value.toLowerCase().indexOf(typedValue) !== -1));
+          }).on("accept", function(selected) {
+            if (d2.isAutoStreetPlace) {
+              d2.id = selected ? selected.type : "street";
+              utilTriggerEvent(select_default2(this), "change");
+            }
+          })
+        );
+      }
+      _wrap.selectAll("input").on("blur", change()).on("change", change());
+      _wrap.selectAll("input:not(.combobox-input)").on("input", change(true));
+      if (_tags) updateTags(_tags);
+    }
+    function address(selection2) {
+      _selection = selection2;
+      _wrap = selection2.selectAll(".form-field-input-wrap").data([0]);
+      _wrap = _wrap.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(_wrap);
+      var extent = combinedEntityExtent();
+      if (extent) {
+        var countryCode;
+        if (context.inIntro()) {
+          countryCode = _t("intro.graph.countrycode");
+        } else {
+          var center = extent.center();
+          countryCode = iso1A2Code(center);
+        }
+        if (countryCode) {
+          _countryCode = countryCode.toLowerCase();
+          updateForCountryCode();
+        }
+      }
+    }
+    function change(onInput) {
+      return function() {
+        var tags = {};
+        _wrap.selectAll("input").each(function(subfield) {
+          var key = field.key + ":" + subfield.id;
+          var value = this.value;
+          if (!onInput) value = context.cleanTagValue(value);
+          if (Array.isArray(_tags[key]) && !value) return;
+          if (subfield.isAutoStreetPlace) {
+            if (subfield.id === "street") {
+              tags["".concat(field.key, ":place")] = void 0;
+            } else if (subfield.id === "place") {
+              tags["".concat(field.key, ":street")] = void 0;
+            }
+          }
+          tags[key] = value || void 0;
+        });
+        Object.keys(tags).filter((k2) => tags[k2]).forEach((k2) => _tags[k2] = tags[k2]);
+        dispatch14.call("change", this, tags, onInput);
+      };
+    }
+    function updatePlaceholder(inputSelection) {
+      return inputSelection.attr("placeholder", function(subfield) {
+        if (_tags && Array.isArray(_tags[field.key + ":" + subfield.id])) {
+          return _t("inspector.multiple_values");
+        }
+        if (subfield.isAutoStreetPlace) {
+          return "".concat(getLocalPlaceholder("street"), " / ").concat(getLocalPlaceholder("place"));
+        }
+        return getLocalPlaceholder(subfield.id);
+      });
+    }
+    function getLocalPlaceholder(key) {
+      if (_countryCode) {
+        var localkey = key + "!" + _countryCode;
+        var tkey = addrField.hasTextForStringId("placeholders." + localkey) ? localkey : key;
+        return addrField.t("placeholders." + tkey);
+      }
+    }
+    function updateTags(tags) {
+      utilGetSetValue(_wrap.selectAll("input"), (subfield) => {
+        var val;
+        if (subfield.isAutoStreetPlace) {
+          const streetKey = "".concat(field.key, ":street");
+          const placeKey = "".concat(field.key, ":place");
+          if (tags[streetKey] !== void 0 || tags[placeKey] === void 0) {
+            val = tags[streetKey];
+            subfield.id = "street";
+          } else {
+            val = tags[placeKey];
+            subfield.id = "place";
+          }
+        } else {
+          val = tags["".concat(field.key, ":").concat(subfield.id)];
+        }
+        return typeof val === "string" ? val : "";
+      }).attr("title", function(subfield) {
+        var val = tags[field.key + ":" + subfield.id];
+        return val && Array.isArray(val) ? val.filter(Boolean).join("\n") : void 0;
+      }).classed("mixed", function(subfield) {
+        return Array.isArray(tags[field.key + ":" + subfield.id]);
+      }).call(updatePlaceholder);
+    }
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    address.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return address;
+    };
+    address.tags = function(tags) {
+      _tags = tags;
+      updateTags(tags);
+    };
+    address.focus = function() {
+      var node = _wrap.selectAll("input").node();
+      if (node) node.focus();
+    };
+    return utilRebind(address, dispatch14, "on");
+  }
+
+  // modules/ui/fields/directional_combo.js
+  function uiFieldDirectionalCombo(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var items = select_default2(null);
+    var wrap2 = select_default2(null);
+    var _tags;
+    var _combos = {};
+    if (field.type === "cycleway") {
+      field = {
+        ...field,
+        key: field.keys[0],
+        keys: field.keys.slice(1)
+      };
+    }
+    function directionalCombo(selection2) {
+      function stripcolon(s2) {
+        return s2.replace(":", "");
+      }
+      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var div = wrap2.selectAll("ul").data([0]);
+      div = div.enter().append("ul").attr("class", "rows rows-table").merge(div);
+      items = div.selectAll("li").data(field.keys);
+      var enter = items.enter().append("li").attr("class", function(d2) {
+        return "labeled-input preset-directionalcombo-" + stripcolon(d2);
+      });
+      enter.append("div").attr("class", "label preset-label-directionalcombo").attr("for", function(d2) {
+        return "preset-input-directionalcombo-" + stripcolon(d2);
+      }).html(function(d2) {
+        return field.t.html("types." + d2);
+      });
+      enter.append("div").attr("class", "preset-input-directionalcombo-wrap form-field-input-wrap").each(function(key) {
+        const subField = {
+          ...field,
+          type: "combo",
+          key
+        };
+        const combo = uiFieldCombo(subField, context);
+        combo.on("change", (t2) => change(key, t2[key]));
+        _combos[key] = combo;
+        select_default2(this).call(combo);
+      });
+      items = items.merge(enter);
+      wrap2.selectAll(".preset-input-directionalcombo").on("change", change).on("blur", change);
+    }
+    function change(key, newValue) {
+      const commonKey = field.key;
+      const otherKey = key === field.keys[0] ? field.keys[1] : field.keys[0];
+      dispatch14.call("change", this, (tags) => {
+        const otherValue = tags[otherKey] || tags[commonKey];
+        if (newValue === otherValue) {
+          tags[commonKey] = newValue;
+          delete tags[key];
+          delete tags[otherKey];
+        } else {
+          tags[key] = newValue;
+          delete tags[commonKey];
+          tags[otherKey] = otherValue;
+        }
+        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] });
+      }
+    };
+    directionalCombo.focus = function() {
+      var node = wrap2.selectAll("input").node();
+      if (node) node.focus();
+    };
+    return utilRebind(directionalCombo, dispatch14, "on");
+  }
+
+  // modules/ui/fields/lanes.js
+  function uiFieldLanes(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var LANE_WIDTH = 40;
+    var LANE_HEIGHT = 200;
+    var _entityIDs = [];
+    function lanes(selection2) {
+      var lanesData = context.entity(_entityIDs[0]).lanes();
+      if (!context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode) {
+        selection2.call(lanes.off);
+        return;
+      }
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var surface = wrap2.selectAll(".surface").data([0]);
+      var d2 = utilGetDimensions(wrap2);
+      var freeSpace = d2[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
+      surface = surface.enter().append("svg").attr("width", d2[0]).attr("height", 300).attr("class", "surface").merge(surface);
+      var lanesSelection = surface.selectAll(".lanes").data([0]);
+      lanesSelection = lanesSelection.enter().append("g").attr("class", "lanes").merge(lanesSelection);
+      lanesSelection.attr("transform", function() {
+        return "translate(" + freeSpace / 2 + ", 0)";
+      });
+      var lane = lanesSelection.selectAll(".lane").data(lanesData.lanes);
+      lane.exit().remove();
+      var enter = lane.enter().append("g").attr("class", "lane");
+      enter.append("g").append("rect").attr("y", 50).attr("width", LANE_WIDTH).attr("height", LANE_HEIGHT);
+      enter.append("g").attr("class", "forward").append("text").attr("y", 40).attr("x", 14).text("\u25B2");
+      enter.append("g").attr("class", "bothways").append("text").attr("y", 40).attr("x", 14).text("\u25B2\u25BC");
+      enter.append("g").attr("class", "backward").append("text").attr("y", 40).attr("x", 14).text("\u25BC");
+      lane = lane.merge(enter);
+      lane.attr("transform", function(d4) {
+        return "translate(" + LANE_WIDTH * d4.index * 1.5 + ", 0)";
+      });
+      lane.select(".forward").style("visibility", function(d4) {
+        return d4.direction === "forward" ? "visible" : "hidden";
+      });
+      lane.select(".bothways").style("visibility", function(d4) {
+        return d4.direction === "bothways" ? "visible" : "hidden";
+      });
+      lane.select(".backward").style("visibility", function(d4) {
+        return d4.direction === "backward" ? "visible" : "hidden";
+      });
+    }
+    lanes.entityIDs = function(val) {
+      _entityIDs = val;
+    };
+    lanes.tags = function() {
+    };
+    lanes.focus = function() {
+    };
+    lanes.off = function() {
+    };
+    return utilRebind(lanes, dispatch14, "on");
+  }
+  uiFieldLanes.supportsMultiselection = false;
+
+  // modules/ui/fields/localized.js
+  var _languagesArray = [];
+  var LANGUAGE_SUFFIX_REGEX = /^(.*):([a-z]{2,3}(?:-[A-Z][a-z]{3})?(?:-[A-Z]{2})?)$/;
+  function uiFieldLocalized(field, context) {
+    var dispatch14 = dispatch_default("change", "input");
+    var wikipedia = services.wikipedia;
+    var input = select_default2(null);
+    var localizedInputs = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue());
+    var _countryCode;
+    var _tags;
+    _mainFileFetcher.get("languages").then(loadLanguagesArray).catch(function() {
+    });
+    var _territoryLanguages = {};
+    _mainFileFetcher.get("territory_languages").then(function(d2) {
+      _territoryLanguages = d2;
+    }).catch(function() {
+    });
+    var langCombo = uiCombobox(context, "localized-lang").fetcher(fetchLanguages).minItems(0);
+    var _selection = select_default2(null);
+    var _multilingual = [];
+    var _buttonTip = uiTooltip().title(() => _t.append("translate.translate")).placement("left");
+    var _wikiTitles;
+    var _entityIDs = [];
+    function loadLanguagesArray(dataLanguages) {
+      if (_languagesArray.length !== 0) return;
+      var replacements = {
+        sr: "sr-Cyrl",
+        // in OSM, `sr` implies Cyrillic
+        "sr-Cyrl": false
+        // `sr-Cyrl` isn't used in OSM
+      };
+      for (var code in dataLanguages) {
+        if (replacements[code] === false) continue;
+        var metaCode = code;
+        if (replacements[code]) metaCode = replacements[code];
+        _languagesArray.push({
+          localName: _mainLocalizer.languageName(metaCode, { localOnly: true }),
+          nativeName: dataLanguages[metaCode].nativeName,
+          code,
+          label: _mainLocalizer.languageName(metaCode)
+        });
+      }
+    }
+    function calcLocked() {
+      var isLocked = field.id === "name" && _entityIDs.length && _entityIDs.some(function(entityID) {
+        var entity = context.graph().hasEntity(entityID);
+        if (!entity) return false;
+        if (entity.tags.wikidata) return true;
+        if (entity.tags["name:etymology:wikidata"]) return true;
+        var preset = _mainPresetIndex.match(entity, context.graph());
+        if (preset) {
+          var isSuggestion = preset.suggestion;
+          var fields = preset.fields(entity.extent(context.graph()).center());
+          var showsBrandField = fields.some(function(d2) {
+            return d2.id === "brand";
+          });
+          var showsOperatorField = fields.some(function(d2) {
+            return d2.id === "operator";
+          });
+          var setsName = preset.addTags.name;
+          var setsBrandWikidata = preset.addTags["brand:wikidata"];
+          var setsOperatorWikidata = preset.addTags["operator:wikidata"];
+          return isSuggestion && setsName && (setsBrandWikidata && !showsBrandField || setsOperatorWikidata && !showsOperatorField);
+        }
+        return false;
+      });
+      field.locked(isLocked);
+    }
+    function calcMultilingual(tags) {
+      var existingLangsOrdered = _multilingual.map(function(item2) {
+        return item2.lang;
+      });
+      var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
+      for (var k2 in tags) {
+        var m2 = k2.match(LANGUAGE_SUFFIX_REGEX);
+        if (m2 && m2[1] === field.key && m2[2]) {
+          var item = { lang: m2[2], value: tags[k2] };
+          if (existingLangs.has(item.lang)) {
+            _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
+            existingLangs.delete(item.lang);
+          } else {
+            _multilingual.push(item);
+          }
+        }
+      }
+      _multilingual.forEach(function(item2) {
+        if (item2.lang && existingLangs.has(item2.lang)) {
+          item2.value = "";
+        }
+      });
+    }
+    function localized(selection2) {
+      _selection = selection2;
+      calcLocked();
+      var isLocked = field.locked();
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      input = wrap2.selectAll(".localized-main").data([0]);
+      input = input.enter().append("input").attr("type", "text").attr("id", field.domId).attr("class", "localized-main").call(utilNoAuto).merge(input);
+      input.classed("disabled", !!isLocked).attr("readonly", isLocked || null).on("input", change(true)).on("blur", change()).on("change", change());
+      wrap2.call(_lengthIndicator);
+      var translateButton = wrap2.selectAll(".localized-add").data([0]);
+      translateButton = translateButton.enter().append("button").attr("class", "localized-add form-field-button").attr("aria-label", _t("icons.plus")).call(svgIcon("#iD-icon-plus")).merge(translateButton);
+      translateButton.classed("disabled", !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on("click", addNew);
+      if (_tags && !_multilingual.length) {
+        calcMultilingual(_tags);
+      }
+      localizedInputs = selection2.selectAll(".localized-multilingual").data([0]);
+      localizedInputs = localizedInputs.enter().append("div").attr("class", "localized-multilingual").merge(localizedInputs);
+      localizedInputs.call(renderMultilingual);
+      localizedInputs.selectAll("button, input").classed("disabled", !!isLocked).attr("readonly", isLocked || null);
+      selection2.selectAll(".combobox-caret").classed("nope", true);
+      function addNew(d3_event) {
+        d3_event.preventDefault();
+        if (field.locked()) return;
+        var defaultLang = _mainLocalizer.languageCode().toLowerCase();
+        var langExists = _multilingual.find(function(datum2) {
+          return datum2.lang === defaultLang;
+        });
+        var isLangEn = defaultLang.indexOf("en") > -1;
+        if (isLangEn || langExists) {
+          defaultLang = "";
+          langExists = _multilingual.find(function(datum2) {
+            return datum2.lang === defaultLang;
+          });
+        }
+        if (!langExists) {
+          _multilingual.unshift({ lang: defaultLang, value: "" });
+          localizedInputs.call(renderMultilingual);
+        }
+      }
+      function change(onInput) {
+        return function(d3_event) {
+          if (field.locked()) {
+            d3_event.preventDefault();
+            return;
+          }
+          var val = utilGetSetValue(select_default2(this));
+          if (!onInput) val = context.cleanTagValue(val);
+          if (!val && Array.isArray(_tags[field.key])) return;
+          var t2 = {};
+          t2[field.key] = val || void 0;
+          dispatch14.call("change", this, t2, onInput);
+        };
+      }
+    }
+    function key(lang) {
+      return field.key + ":" + lang;
+    }
+    function changeLang(d3_event, d2) {
+      var tags = {};
+      var lang = utilGetSetValue(select_default2(this)).toLowerCase();
+      var language = _languagesArray.find(function(d4) {
+        return d4.label.toLowerCase() === lang || d4.localName && d4.localName.toLowerCase() === lang || d4.nativeName && d4.nativeName.toLowerCase() === lang;
+      });
+      if (language) lang = language.code;
+      if (d2.lang && d2.lang !== lang) {
+        tags[key(d2.lang)] = void 0;
+      }
+      var newKey = lang && context.cleanTagKey(key(lang));
+      var value = utilGetSetValue(select_default2(this.parentNode).selectAll(".localized-value"));
+      if (newKey && value) {
+        tags[newKey] = value;
+      } else if (newKey && _wikiTitles && _wikiTitles[d2.lang]) {
+        tags[newKey] = _wikiTitles[d2.lang];
+      }
+      d2.lang = lang;
+      dispatch14.call("change", this, tags);
+    }
+    function changeValue(d3_event, d2) {
+      if (!d2.lang) return;
+      var value = context.cleanTagValue(utilGetSetValue(select_default2(this))) || void 0;
+      if (!value && Array.isArray(d2.value)) return;
+      var t2 = {};
+      t2[key(d2.lang)] = value;
+      d2.value = value;
+      dispatch14.call("change", this, t2);
+    }
+    function fetchLanguages(value, cb) {
+      var v2 = value.toLowerCase();
+      var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
+      if (_countryCode && _territoryLanguages[_countryCode]) {
+        langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
+      }
+      var langItems = [];
+      langCodes.forEach(function(code) {
+        var langItem = _languagesArray.find(function(item) {
+          return item.code === code;
+        });
+        if (langItem) langItems.push(langItem);
+      });
+      langItems = utilArrayUniq(langItems.concat(_languagesArray));
+      cb(langItems.filter(function(d2) {
+        return d2.label.toLowerCase().indexOf(v2) >= 0 || d2.localName && d2.localName.toLowerCase().indexOf(v2) >= 0 || d2.nativeName && d2.nativeName.toLowerCase().indexOf(v2) >= 0 || d2.code.toLowerCase().indexOf(v2) >= 0;
+      }).map(function(d2) {
+        return { value: d2.label };
+      }));
+    }
+    function renderMultilingual(selection2) {
+      var entries = selection2.selectAll("div.entry").data(_multilingual, function(d2) {
+        return d2.lang;
+      });
+      entries.exit().style("top", "0").style("max-height", "240px").transition().duration(200).style("opacity", "0").style("max-height", "0px").remove();
+      var entriesEnter = entries.enter().append("div").attr("class", "entry").each(function(_2, index) {
+        var wrap2 = select_default2(this);
+        var domId = utilUniqueDomId(index);
+        var label = wrap2.append("label").attr("class", "field-label").attr("for", domId);
+        var text = label.append("span").attr("class", "label-text");
+        text.append("span").attr("class", "label-textvalue").call(_t.append("translate.localized_translation_label"));
+        text.append("span").attr("class", "label-textannotation");
+        label.append("button").attr("class", "remove-icon-multilingual").attr("title", _t("icons.remove")).on("click", function(d3_event, d2) {
+          if (field.locked()) return;
+          d3_event.preventDefault();
+          _multilingual.splice(_multilingual.indexOf(d2), 1);
+          var langKey = d2.lang && key(d2.lang);
+          if (langKey && langKey in _tags) {
+            delete _tags[langKey];
+            var t2 = {};
+            t2[langKey] = void 0;
+            dispatch14.call("change", this, t2);
+            return;
+          }
+          renderMultilingual(selection2);
+        }).call(svgIcon("#iD-operation-delete"));
+        wrap2.append("input").attr("class", "localized-lang").attr("id", domId).attr("type", "text").attr("placeholder", _t("translate.localized_translation_language")).on("blur", changeLang).on("change", changeLang).call(langCombo);
+        wrap2.append("input").attr("type", "text").attr("class", "localized-value").on("blur", changeValue).on("change", changeValue);
+      });
+      entriesEnter.style("margin-top", "0px").style("max-height", "0px").style("opacity", "0").transition().duration(200).style("margin-top", "10px").style("max-height", "240px").style("opacity", "1").on("end", function() {
+        select_default2(this).style("max-height", "").style("overflow", "visible");
+      });
+      entries = entries.merge(entriesEnter);
+      entries.order();
+      entries.classed("present", true);
+      utilGetSetValue(entries.select(".localized-lang"), function(d2) {
+        var langItem = _languagesArray.find(function(item) {
+          return item.code === d2.lang;
+        });
+        if (langItem) return langItem.label;
+        return d2.lang;
+      });
+      utilGetSetValue(entries.select(".localized-value"), function(d2) {
+        return typeof d2.value === "string" ? d2.value : "";
+      }).attr("title", function(d2) {
+        return Array.isArray(d2.value) ? d2.value.filter(Boolean).join("\n") : null;
+      }).attr("placeholder", function(d2) {
+        return Array.isArray(d2.value) ? _t("inspector.multiple_values") : _t("translate.localized_translation_name");
+      }).classed("mixed", function(d2) {
+        return Array.isArray(d2.value);
+      });
+    }
+    localized.tags = function(tags) {
+      _tags = tags;
+      if (typeof tags.wikipedia === "string" && !_wikiTitles) {
+        _wikiTitles = {};
+        var wm = tags.wikipedia.match(/([^:]+):(.+)/);
+        if (wm && wm[0] && wm[1]) {
+          wikipedia.translations(wm[1], wm[2], function(err, d2) {
+            if (err || !d2) return;
+            _wikiTitles = d2;
+          });
+        }
+      }
+      var isMixed = Array.isArray(tags[field.key]);
+      utilGetSetValue(input, typeof tags[field.key] === "string" ? tags[field.key] : "").attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
+      calcMultilingual(tags);
+      _selection.call(localized);
+      if (!isMixed) {
+        _lengthIndicator.update(tags[field.key]);
+      }
+    };
+    localized.focus = function() {
+      input.node().focus();
+    };
+    localized.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _multilingual = [];
+      loadCountryCode();
+      return localized;
+    };
+    function loadCountryCode() {
+      var extent = combinedEntityExtent();
+      var countryCode = extent && iso1A2Code(extent.center());
+      _countryCode = countryCode && countryCode.toLowerCase();
+    }
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    return utilRebind(localized, dispatch14, "on");
+  }
+
+  // modules/ui/fields/roadheight.js
+  function uiFieldRoadheight(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var primaryUnitInput = select_default2(null);
+    var primaryInput = select_default2(null);
+    var secondaryInput = select_default2(null);
+    var secondaryUnitInput = select_default2(null);
+    var _entityIDs = [];
+    var _tags;
+    var _isImperial;
+    var formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
+    var parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
+    var primaryUnits = [
+      {
+        value: "m",
+        title: _t("inspector.roadheight.meter")
+      },
+      {
+        value: "ft",
+        title: _t("inspector.roadheight.foot")
+      }
+    ];
+    var unitCombo = uiCombobox(context, "roadheight-unit").data(primaryUnits);
+    function roadheight(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      primaryInput = wrap2.selectAll("input.roadheight-number").data([0]);
+      primaryInput = primaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-number").attr("id", field.domId).call(utilNoAuto).merge(primaryInput);
+      primaryInput.on("change", change).on("blur", change);
+      var loc = combinedEntityExtent().center();
+      _isImperial = roadHeightUnit(loc) === "ft";
+      primaryUnitInput = wrap2.selectAll("input.roadheight-unit").data([0]);
+      primaryUnitInput = primaryUnitInput.enter().append("input").attr("type", "text").attr("class", "roadheight-unit").call(unitCombo).merge(primaryUnitInput);
+      primaryUnitInput.on("blur", changeUnits).on("change", changeUnits);
+      secondaryInput = wrap2.selectAll("input.roadheight-secondary-number").data([0]);
+      secondaryInput = secondaryInput.enter().append("input").attr("type", "text").attr("class", "roadheight-secondary-number").call(utilNoAuto).merge(secondaryInput);
+      secondaryInput.on("change", change).on("blur", change);
+      secondaryUnitInput = wrap2.selectAll("input.roadheight-secondary-unit").data([0]);
+      secondaryUnitInput = secondaryUnitInput.enter().append("input").attr("type", "text").call(utilNoAuto).classed("disabled", true).classed("roadheight-secondary-unit", true).attr("readonly", "readonly").merge(secondaryUnitInput);
+      function changeUnits() {
+        var primaryUnit = utilGetSetValue(primaryUnitInput);
+        if (primaryUnit === "m") {
+          _isImperial = false;
+        } else if (primaryUnit === "ft") {
+          _isImperial = true;
+        }
+        utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
+        setUnitSuggestions();
+        change();
+      }
+    }
+    function setUnitSuggestions() {
+      utilGetSetValue(primaryUnitInput, _isImperial ? "ft" : "m");
+    }
+    function change() {
+      var tag2 = {};
+      var primaryValue = utilGetSetValue(primaryInput).trim();
+      var secondaryValue = utilGetSetValue(secondaryInput).trim();
+      if (!primaryValue && !secondaryValue && Array.isArray(_tags[field.key])) return;
+      if (!primaryValue && !secondaryValue) {
+        tag2[field.key] = void 0;
+      } else {
+        var rawPrimaryValue = likelyRawNumberFormat.test(primaryValue) ? parseFloat(primaryValue) : parseLocaleFloat(primaryValue);
+        if (isNaN(rawPrimaryValue)) rawPrimaryValue = primaryValue;
+        var rawSecondaryValue = likelyRawNumberFormat.test(secondaryValue) ? parseFloat(secondaryValue) : parseLocaleFloat(secondaryValue);
+        if (isNaN(rawSecondaryValue)) rawSecondaryValue = secondaryValue;
+        if (isNaN(rawPrimaryValue) || isNaN(rawSecondaryValue) || !_isImperial) {
+          tag2[field.key] = context.cleanTagValue(rawPrimaryValue);
+        } else {
+          if (rawPrimaryValue !== "") {
+            rawPrimaryValue = rawPrimaryValue + "'";
+          }
+          if (rawSecondaryValue !== "") {
+            rawSecondaryValue = rawSecondaryValue + '"';
+          }
+          tag2[field.key] = context.cleanTagValue(rawPrimaryValue + rawSecondaryValue);
+        }
+      }
+      dispatch14.call("change", this, tag2);
+    }
+    roadheight.tags = function(tags) {
+      _tags = tags;
+      var primaryValue = tags[field.key];
+      var secondaryValue;
+      var isMixed = Array.isArray(primaryValue);
+      if (!isMixed) {
+        if (primaryValue && (primaryValue.indexOf("'") >= 0 || primaryValue.indexOf('"') >= 0)) {
+          secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
+          if (secondaryValue !== null) {
+            secondaryValue = formatFloat(parseFloat(secondaryValue[1]));
+          }
+          primaryValue = primaryValue.match(/(-?[\d.]+)'/);
+          if (primaryValue !== null) {
+            primaryValue = formatFloat(parseFloat(primaryValue[1]));
+          }
+          _isImperial = true;
+        } else if (primaryValue) {
+          var rawValue = primaryValue;
+          primaryValue = parseFloat(rawValue);
+          if (isNaN(primaryValue)) {
+            primaryValue = rawValue;
+          } else {
+            primaryValue = formatFloat(primaryValue);
+          }
+          _isImperial = false;
+        }
+      }
+      setUnitSuggestions();
+      var inchesPlaceholder = formatFloat(0);
+      utilGetSetValue(primaryInput, typeof primaryValue === "string" ? primaryValue : "").attr("title", isMixed ? primaryValue.filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : _t("inspector.unknown")).classed("mixed", isMixed);
+      utilGetSetValue(secondaryInput, typeof secondaryValue === "string" ? secondaryValue : "").attr("placeholder", isMixed ? _t("inspector.multiple_values") : _isImperial ? inchesPlaceholder : null).classed("mixed", isMixed).classed("disabled", !_isImperial).attr("readonly", _isImperial ? null : "readonly");
+      secondaryUnitInput.attr("value", _isImperial ? _t("inspector.roadheight.inch") : null);
+    };
+    roadheight.focus = function() {
+      primaryInput.node().focus();
+    };
+    roadheight.entityIDs = function(val) {
+      _entityIDs = val;
+    };
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    return utilRebind(roadheight, dispatch14, "on");
+  }
+
+  // modules/ui/fields/roadspeed.js
+  function uiFieldRoadspeed(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var unitInput = select_default2(null);
+    var input = select_default2(null);
+    var _entityIDs = [];
+    var _tags;
+    var _isImperial;
+    var formatFloat = _mainLocalizer.floatFormatter(_mainLocalizer.languageCode());
+    var parseLocaleFloat = _mainLocalizer.floatParser(_mainLocalizer.languageCode());
+    var speedCombo = uiCombobox(context, "roadspeed");
+    var unitCombo = uiCombobox(context, "roadspeed-unit").data(["km/h", "mph"].map(comboValues));
+    var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
+    var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
+    function roadspeed(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      input = wrap2.selectAll("input.roadspeed-number").data([0]);
+      input = input.enter().append("input").attr("type", "text").attr("class", "roadspeed-number").attr("id", field.domId).call(utilNoAuto).call(speedCombo).merge(input);
+      input.on("change", change).on("blur", change);
+      var loc = combinedEntityExtent().center();
+      _isImperial = roadSpeedUnit(loc) === "mph";
+      unitInput = wrap2.selectAll("input.roadspeed-unit").data([0]);
+      unitInput = unitInput.enter().append("input").attr("type", "text").attr("class", "roadspeed-unit").attr("aria-label", _t("inspector.speed_unit")).call(unitCombo).merge(unitInput);
+      unitInput.on("blur", changeUnits).on("change", changeUnits);
+      function changeUnits() {
+        var unit2 = utilGetSetValue(unitInput);
+        if (unit2 === "km/h") {
+          _isImperial = false;
+        } else if (unit2 === "mph") {
+          _isImperial = true;
+        }
+        utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
+        setUnitSuggestions();
+        change();
+      }
+    }
+    function setUnitSuggestions() {
+      speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
+      utilGetSetValue(unitInput, _isImperial ? "mph" : "km/h");
+    }
+    function comboValues(d2) {
+      return {
+        value: formatFloat(d2),
+        title: formatFloat(d2)
+      };
+    }
+    function change() {
+      var tag2 = {};
+      var value = utilGetSetValue(input).trim();
+      if (!value && Array.isArray(_tags[field.key])) return;
+      if (!value) {
+        tag2[field.key] = void 0;
+      } else {
+        var rawValue = likelyRawNumberFormat.test(value) ? parseFloat(value) : parseLocaleFloat(value);
+        if (isNaN(rawValue)) rawValue = value;
+        if (isNaN(rawValue) || !_isImperial) {
+          tag2[field.key] = context.cleanTagValue(rawValue);
+        } else {
+          tag2[field.key] = context.cleanTagValue(rawValue + " mph");
+        }
+      }
+      dispatch14.call("change", this, tag2);
+    }
+    roadspeed.tags = function(tags) {
+      _tags = tags;
+      var rawValue = tags[field.key];
+      var value = rawValue;
+      var isMixed = Array.isArray(value);
+      if (!isMixed) {
+        if (rawValue && rawValue.indexOf("mph") >= 0) {
+          _isImperial = true;
+        } else if (rawValue) {
+          _isImperial = false;
+        }
+        value = parseInt(value, 10);
+        if (isNaN(value)) {
+          value = rawValue;
+        } else {
+          value = formatFloat(value);
+        }
+      }
+      setUnitSuggestions();
+      utilGetSetValue(input, typeof value === "string" ? value : "").attr("title", isMixed ? value.filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder()).classed("mixed", isMixed);
+    };
+    roadspeed.focus = function() {
+      input.node().focus();
+    };
+    roadspeed.entityIDs = function(val) {
+      _entityIDs = val;
+    };
+    function combinedEntityExtent() {
+      return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
+    }
+    return utilRebind(roadspeed, dispatch14, "on");
+  }
+
+  // modules/ui/fields/radio.js
+  function uiFieldRadio(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var placeholder = select_default2(null);
+    var wrap2 = select_default2(null);
+    var labels = select_default2(null);
+    var radios = select_default2(null);
+    var radioData = (field.options || field.keys).slice();
+    var typeField;
+    var layerField;
+    var _oldType = {};
+    var _entityIDs = [];
+    function selectedKey() {
+      var node = wrap2.selectAll(".form-field-input-radio label.active input");
+      return !node.empty() && node.datum();
+    }
+    function radio(selection2) {
+      selection2.classed("preset-radio", true);
+      wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      var enter = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-radio");
+      enter.append("span").attr("class", "placeholder");
+      wrap2 = wrap2.merge(enter);
+      placeholder = wrap2.selectAll(".placeholder");
+      labels = wrap2.selectAll("label").data(radioData);
+      enter = labels.enter().append("label");
+      var stringsField = field.resolveReference("stringsCrossReference");
+      enter.append("input").attr("type", "radio").attr("name", field.id).attr("value", function(d2) {
+        return stringsField.t("options." + d2, { "default": d2 });
+      }).attr("checked", false);
+      enter.append("span").each(function(d2) {
+        stringsField.t.append("options." + d2, { "default": d2 })(select_default2(this));
+      });
+      labels = labels.merge(enter);
+      radios = labels.selectAll("input").on("change", changeRadio);
+    }
+    function structureExtras(selection2, tags) {
+      var selected = selectedKey() || tags.layer !== void 0;
+      var type2 = _mainPresetIndex.field(selected);
+      var layer = _mainPresetIndex.field("layer");
+      var showLayer = selected === "bridge" || selected === "tunnel" || tags.layer !== void 0;
+      var extrasWrap = selection2.selectAll(".structure-extras-wrap").data(selected ? [0] : []);
+      extrasWrap.exit().remove();
+      extrasWrap = extrasWrap.enter().append("div").attr("class", "structure-extras-wrap").merge(extrasWrap);
+      var list2 = extrasWrap.selectAll("ul").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
+      if (type2) {
+        if (!typeField || typeField.id !== selected) {
+          typeField = uiField(context, type2, _entityIDs, { wrap: false }).on("change", changeType);
+        }
+        typeField.tags(tags);
+      } else {
+        typeField = null;
+      }
+      var typeItem = list2.selectAll(".structure-type-item").data(typeField ? [typeField] : [], function(d2) {
+        return d2.id;
+      });
+      typeItem.exit().remove();
+      var typeEnter = typeItem.enter().insert("li", ":first-child").attr("class", "labeled-input structure-type-item");
+      typeEnter.append("div").attr("class", "label structure-label-type").attr("for", "preset-input-" + selected).call(_t.append("inspector.radio.structure.type"));
+      typeEnter.append("div").attr("class", "structure-input-type-wrap");
+      typeItem = typeItem.merge(typeEnter);
+      if (typeField) {
+        typeItem.selectAll(".structure-input-type-wrap").call(typeField.render);
+      }
+      if (layer && showLayer) {
+        if (!layerField) {
+          layerField = uiField(context, layer, _entityIDs, { wrap: false }).on("change", changeLayer);
+        }
+        layerField.tags(tags);
+        field.keys = utilArrayUnion(field.keys, ["layer"]);
+      } else {
+        layerField = null;
+        field.keys = field.keys.filter(function(k2) {
+          return k2 !== "layer";
+        });
+      }
+      var layerItem = list2.selectAll(".structure-layer-item").data(layerField ? [layerField] : []);
+      layerItem.exit().remove();
+      var layerEnter = layerItem.enter().append("li").attr("class", "labeled-input structure-layer-item");
+      layerEnter.append("div").attr("class", "label structure-label-layer").attr("for", "preset-input-layer").call(_t.append("inspector.radio.structure.layer"));
+      layerEnter.append("div").attr("class", "structure-input-layer-wrap");
+      layerItem = layerItem.merge(layerEnter);
+      if (layerField) {
+        layerItem.selectAll(".structure-input-layer-wrap").call(layerField.render);
+      }
+    }
+    function changeType(t2, onInput) {
+      var key = selectedKey();
+      if (!key) return;
+      var val = t2[key];
+      if (val !== "no") {
+        _oldType[key] = val;
+      }
+      if (field.type === "structureRadio") {
+        if (val === "no" || key !== "bridge" && key !== "tunnel" || key === "tunnel" && val === "building_passage") {
+          t2.layer = void 0;
+        }
+        if (t2.layer === void 0) {
+          if (key === "bridge" && val !== "no") {
+            t2.layer = "1";
+          }
+          if (key === "tunnel" && val !== "no" && val !== "building_passage") {
+            t2.layer = "-1";
+          }
+        }
+      }
+      dispatch14.call("change", this, t2, onInput);
+    }
+    function changeLayer(t2, onInput) {
+      if (t2.layer === "0") {
+        t2.layer = void 0;
+      }
+      dispatch14.call("change", this, t2, onInput);
+    }
+    function changeRadio() {
+      var t2 = {};
+      var activeKey;
+      if (field.key) {
+        t2[field.key] = void 0;
+      }
+      radios.each(function(d2) {
+        var active = select_default2(this).property("checked");
+        if (active) activeKey = d2;
+        if (field.key) {
+          if (active) t2[field.key] = d2;
+        } else {
+          var val = _oldType[activeKey] || "yes";
+          t2[d2] = active ? val : void 0;
+        }
+      });
+      if (field.type === "structureRadio") {
+        if (activeKey === "bridge") {
+          t2.layer = "1";
+        } else if (activeKey === "tunnel" && t2.tunnel !== "building_passage") {
+          t2.layer = "-1";
+        } else {
+          t2.layer = void 0;
+        }
+      }
+      dispatch14.call("change", this, t2);
+    }
+    radio.tags = function(tags) {
+      function isOptionChecked(d2) {
+        if (field.key) {
+          return tags[field.key] === d2;
+        }
+        return !!(typeof tags[d2] === "string" && tags[d2].toLowerCase() !== "no");
+      }
+      function isMixed(d2) {
+        if (field.key) {
+          return Array.isArray(tags[field.key]) && tags[field.key].includes(d2);
+        }
+        return Array.isArray(tags[d2]);
+      }
+      radios.property("checked", function(d2) {
+        return isOptionChecked(d2) && (field.key || field.options.filter(isOptionChecked).length === 1);
+      });
+      labels.classed("active", function(d2) {
+        if (field.key) {
+          return Array.isArray(tags[field.key]) && tags[field.key].includes(d2) || tags[field.key] === d2;
+        }
+        return Array.isArray(tags[d2]) && tags[d2].some((v2) => typeof v2 === "string" && v2.toLowerCase() !== "no") || !!(typeof tags[d2] === "string" && tags[d2].toLowerCase() !== "no");
+      }).classed("mixed", isMixed).attr("title", function(d2) {
+        return isMixed(d2) ? _t("inspector.unshared_value_tooltip") : null;
+      });
+      var selection2 = radios.filter(function() {
+        return this.checked;
+      });
+      if (selection2.empty()) {
+        placeholder.text("");
+        placeholder.call(_t.append("inspector.none"));
+      } else {
+        placeholder.text(selection2.attr("value"));
+        _oldType[selection2.datum()] = tags[selection2.datum()];
+      }
+      if (field.type === "structureRadio") {
+        if (!!tags.waterway && !_oldType.tunnel) {
+          _oldType.tunnel = "culvert";
+        }
+        wrap2.call(structureExtras, tags);
+      }
+    };
+    radio.focus = function() {
+      radios.node().focus();
+    };
+    radio.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      _oldType = {};
+      return radio;
+    };
+    radio.isAllowed = function() {
+      return _entityIDs.length === 1;
+    };
+    return utilRebind(radio, dispatch14, "on");
+  }
+
+  // modules/ui/fields/restrictions.js
+  function uiFieldRestrictions(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var breathe = behaviorBreathe(context);
+    corePreferences("turn-restriction-via-way", null);
+    var storedViaWay = corePreferences("turn-restriction-via-way0");
+    var storedDistance = corePreferences("turn-restriction-distance");
+    var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
+    var _maxDistance = storedDistance ? +storedDistance : 30;
+    var _initialized3 = false;
+    var _parent = select_default2(null);
+    var _container = select_default2(null);
+    var _oldTurns;
+    var _graph;
+    var _vertexID;
+    var _intersection;
+    var _fromWayID;
+    var _lastXPos;
+    function restrictions(selection2) {
+      _parent = selection2;
+      if (_vertexID && (context.graph() !== _graph || !_intersection)) {
+        _graph = context.graph();
+        _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
+      }
+      var isOK = _intersection && _intersection.vertices.length && // has vertices
+      _intersection.vertices.filter(function(vertex) {
+        return vertex.id === _vertexID;
+      }).length && _intersection.ways.length > 2;
+      select_default2(selection2.node().parentNode).classed("hide", !isOK);
+      if (!isOK || !context.container().select(".inspector-wrap.inspector-hidden").empty() || !selection2.node().parentNode || !selection2.node().parentNode.parentNode) {
+        selection2.call(restrictions.off);
+        return;
+      }
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var container = wrap2.selectAll(".restriction-container").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "restriction-container");
+      containerEnter.append("div").attr("class", "restriction-help");
+      _container = containerEnter.merge(container).call(renderViewer);
+      var controls = wrap2.selectAll(".restriction-controls").data([0]);
+      controls.enter().append("div").attr("class", "restriction-controls-container").append("div").attr("class", "restriction-controls").merge(controls).call(renderControls);
+    }
+    function renderControls(selection2) {
+      var distControl = selection2.selectAll(".restriction-distance").data([0]);
+      distControl.exit().remove();
+      var distControlEnter = distControl.enter().append("div").attr("class", "restriction-control restriction-distance");
+      distControlEnter.append("span").attr("class", "restriction-control-label restriction-distance-label").call(_t.append("restriction.controls.distance", { suffix: ":" }));
+      distControlEnter.append("input").attr("class", "restriction-distance-input").attr("type", "range").attr("min", "20").attr("max", "50").attr("step", "5");
+      distControlEnter.append("span").attr("class", "restriction-distance-text");
+      selection2.selectAll(".restriction-distance-input").property("value", _maxDistance).on("input", function() {
+        var val = select_default2(this).property("value");
+        _maxDistance = +val;
+        _intersection = null;
+        _container.selectAll(".layer-osm .layer-turns *").remove();
+        corePreferences("turn-restriction-distance", _maxDistance);
+        _parent.call(restrictions);
+      });
+      selection2.selectAll(".restriction-distance-text").call(displayMaxDistance(_maxDistance));
+      var viaControl = selection2.selectAll(".restriction-via-way").data([0]);
+      viaControl.exit().remove();
+      var viaControlEnter = viaControl.enter().append("div").attr("class", "restriction-control restriction-via-way");
+      viaControlEnter.append("span").attr("class", "restriction-control-label restriction-via-way-label").call(_t.append("restriction.controls.via", { suffix: ":" }));
+      viaControlEnter.append("input").attr("class", "restriction-via-way-input").attr("type", "range").attr("min", "0").attr("max", "2").attr("step", "1");
+      viaControlEnter.append("span").attr("class", "restriction-via-way-text");
+      selection2.selectAll(".restriction-via-way-input").property("value", _maxViaWay).on("input", function() {
+        var val = select_default2(this).property("value");
+        _maxViaWay = +val;
+        _container.selectAll(".layer-osm .layer-turns *").remove();
+        corePreferences("turn-restriction-via-way0", _maxViaWay);
+        _parent.call(restrictions);
+      });
+      selection2.selectAll(".restriction-via-way-text").call(displayMaxVia(_maxViaWay));
+    }
+    function renderViewer(selection2) {
+      if (!_intersection) return;
+      var vgraph = _intersection.graph;
+      var filter2 = utilFunctor(true);
+      var projection2 = geoRawMercator();
+      var sdims = utilGetDimensions(context.container().select(".sidebar"));
+      var d2 = [sdims[0] - 50, 370];
+      var c2 = geoVecScale(d2, 0.5);
+      var z2 = 22;
+      projection2.scale(geoZoomToScale(z2));
+      var extent = geoExtent();
+      for (var i3 = 0; i3 < _intersection.vertices.length; i3++) {
+        extent._extend(_intersection.vertices[i3].extent());
+      }
+      var padTop = 35;
+      if (_intersection.vertices.length > 1) {
+        var hPadding = Math.min(160, Math.max(110, d2[0] * 0.4));
+        var vPadding = 160;
+        var tl = projection2([extent[0][0], extent[1][1]]);
+        var br2 = projection2([extent[1][0], extent[0][1]]);
+        var hFactor = (br2[0] - tl[0]) / (d2[0] - hPadding);
+        var vFactor = (br2[1] - tl[1]) / (d2[1] - vPadding - padTop);
+        var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
+        var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
+        z2 = z2 - Math.max(hZoomDiff, vZoomDiff);
+        projection2.scale(geoZoomToScale(z2));
+      }
+      var extentCenter = projection2(extent.center());
+      extentCenter[1] = extentCenter[1] - padTop / 2;
+      projection2.translate(geoVecSubtract(c2, extentCenter)).clipExtent([[0, 0], d2]);
+      var drawLayers = svgLayers(projection2, context).only(["osm", "touch"]).dimensions(d2);
+      var drawVertices = svgVertices(projection2, context);
+      var drawLines = svgLines(projection2, context);
+      var drawTurns = svgTurns(projection2, context);
+      var firstTime = selection2.selectAll(".surface").empty();
+      selection2.call(drawLayers);
+      var surface = selection2.selectAll(".surface").classed("tr", true);
+      if (firstTime) {
+        _initialized3 = true;
+        surface.call(breathe);
+      }
+      if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
+        _fromWayID = null;
+        _oldTurns = null;
+      }
+      surface.call(utilSetDimensions, d2).call(drawVertices, vgraph, _intersection.vertices, filter2, extent, z2).call(drawLines, vgraph, _intersection.ways, filter2).call(drawTurns, vgraph, _intersection.turns(_fromWayID, _maxViaWay));
+      surface.on("click.restrictions", click).on("mouseover.restrictions", mouseover);
+      surface.selectAll(".selected").classed("selected", false);
+      surface.selectAll(".related").classed("related", false);
+      var way;
+      if (_fromWayID) {
+        way = vgraph.entity(_fromWayID);
+        surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+      }
+      document.addEventListener("resizeWindow", function() {
+        utilSetDimensions(_container, null);
+        redraw(1);
+      }, false);
+      updateHints(null);
+      function click(d3_event) {
+        surface.call(breathe.off).call(breathe);
+        var datum2 = d3_event.target.__data__;
+        var entity = datum2 && datum2.properties && datum2.properties.entity;
+        if (entity) {
+          datum2 = entity;
+        }
+        if (datum2 instanceof osmWay && (datum2.__from || datum2.__via)) {
+          _fromWayID = datum2.id;
+          _oldTurns = null;
+          redraw();
+        } else if (datum2 instanceof osmTurn) {
+          var actions, extraActions, turns, i4;
+          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
+          if (datum2.restrictionID && !datum2.direct) {
+            return;
+          } else if (datum2.restrictionID && !datum2.only) {
+            var seen = {};
+            var datumOnly = JSON.parse(JSON.stringify(datum2));
+            datumOnly.only = true;
+            restrictionType = restrictionType.replace(/^no/, "only");
+            turns = _intersection.turns(_fromWayID, 2);
+            extraActions = [];
+            _oldTurns = [];
+            for (i4 = 0; i4 < turns.length; i4++) {
+              var turn = turns[i4];
+              if (seen[turn.restrictionID]) continue;
+              if (turn.direct && turn.path[1] === datum2.path[1]) {
+                seen[turns[i4].restrictionID] = true;
+                turn.restrictionType = osmInferRestriction(vgraph, turn, projection2);
+                _oldTurns.push(turn);
+                extraActions.push(actionUnrestrictTurn(turn));
+              }
+            }
+            actions = _intersection.actions.concat(extraActions, [
+              actionRestrictTurn(datumOnly, restrictionType),
+              _t("operations.restriction.annotation.create")
+            ]);
+          } else if (datum2.restrictionID) {
+            turns = _oldTurns || [];
+            extraActions = [];
+            for (i4 = 0; i4 < turns.length; i4++) {
+              if (turns[i4].key !== datum2.key) {
+                extraActions.push(actionRestrictTurn(turns[i4], turns[i4].restrictionType));
+              }
+            }
+            _oldTurns = null;
+            actions = _intersection.actions.concat(extraActions, [
+              actionUnrestrictTurn(datum2),
+              _t("operations.restriction.annotation.delete")
+            ]);
+          } else {
+            actions = _intersection.actions.concat([
+              actionRestrictTurn(datum2, restrictionType),
+              _t("operations.restriction.annotation.create")
+            ]);
+          }
+          context.perform.apply(context, actions);
+          var s2 = surface.selectAll("." + datum2.key);
+          datum2 = s2.empty() ? null : s2.datum();
+          updateHints(datum2);
+        } else {
+          _fromWayID = null;
+          _oldTurns = null;
+          redraw();
+        }
+      }
+      function mouseover(d3_event) {
+        var datum2 = d3_event.target.__data__;
+        updateHints(datum2);
+      }
+      _lastXPos = _lastXPos || sdims[0];
+      function redraw(minChange) {
+        var xPos = -1;
+        if (minChange) {
+          xPos = utilGetDimensions(context.container().select(".sidebar"))[0];
+        }
+        if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
+          if (context.hasEntity(_vertexID)) {
+            _lastXPos = xPos;
+            _container.call(renderViewer);
+          }
+        }
+      }
+      function highlightPathsFrom(wayID) {
+        surface.selectAll(".related").classed("related", false).classed("allow", false).classed("restrict", false).classed("only", false);
+        surface.selectAll("." + wayID).classed("related", true);
+        if (wayID) {
+          var turns = _intersection.turns(wayID, _maxViaWay);
+          for (var i4 = 0; i4 < turns.length; i4++) {
+            var turn = turns[i4];
+            var ids = [turn.to.way];
+            var klass = turn.no ? "restrict" : turn.only ? "only" : "allow";
+            if (turn.only || turns.length === 1) {
+              if (turn.via.ways) {
+                ids = ids.concat(turn.via.ways);
+              }
+            } else if (turn.to.way === wayID) {
+              continue;
+            }
+            surface.selectAll(utilEntitySelector(ids)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
+          }
+        }
+      }
+      function updateHints(datum2) {
+        var help = _container.selectAll(".restriction-help").html("");
+        var placeholders = {};
+        ["from", "via", "to"].forEach(function(k2) {
+          placeholders[k2] = { html: '<span class="qualifier">' + _t("restriction.help." + k2) + "</span>" };
+        });
+        var entity = datum2 && datum2.properties && datum2.properties.entity;
+        if (entity) {
+          datum2 = entity;
+        }
+        if (_fromWayID) {
+          way = vgraph.entity(_fromWayID);
+          surface.selectAll("." + _fromWayID).classed("selected", true).classed("related", true);
+        }
+        if (datum2 instanceof osmWay && datum2.__from) {
+          way = datum2;
+          highlightPathsFrom(_fromWayID ? null : way.id);
+          surface.selectAll("." + way.id).classed("related", true);
+          var clickSelect = !_fromWayID || _fromWayID !== way.id;
+          help.append("div").html(_t.html("restriction.help." + (clickSelect ? "select_from_name" : "from_name"), {
+            from: placeholders.from,
+            fromName: displayName(way.id, vgraph)
+          }));
+        } else if (datum2 instanceof osmTurn) {
+          var restrictionType = osmInferRestriction(vgraph, datum2, projection2);
+          var turnType = restrictionType.replace(/^(only|no)\_/, "");
+          var indirect = datum2.direct === false ? _t.html("restriction.help.indirect") : "";
+          var klass, turnText, nextText;
+          if (datum2.no) {
+            klass = "restrict";
+            turnText = _t.html("restriction.help.turn.no_" + turnType, { indirect: { html: indirect } });
+            nextText = _t.html("restriction.help.turn.only_" + turnType, { indirect: "" });
+          } else if (datum2.only) {
+            klass = "only";
+            turnText = _t.html("restriction.help.turn.only_" + turnType, { indirect: { html: indirect } });
+            nextText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: "" });
+          } else {
+            klass = "allow";
+            turnText = _t.html("restriction.help.turn.allowed_" + turnType, { indirect: { html: indirect } });
+            nextText = _t.html("restriction.help.turn.no_" + turnType, { indirect: "" });
+          }
+          help.append("div").attr("class", "qualifier " + klass).html(turnText);
+          help.append("div").html(_t.html("restriction.help.from_name_to_name", {
+            from: placeholders.from,
+            fromName: displayName(datum2.from.way, vgraph),
+            to: placeholders.to,
+            toName: displayName(datum2.to.way, vgraph)
+          }));
+          if (datum2.via.ways && datum2.via.ways.length) {
+            var names = [];
+            for (var i4 = 0; i4 < datum2.via.ways.length; i4++) {
+              var prev = names[names.length - 1];
+              var curr = displayName(datum2.via.ways[i4], vgraph);
+              if (!prev || curr !== prev) {
+                names.push(curr);
+              }
+            }
+            help.append("div").html(_t.html("restriction.help.via_names", {
+              via: placeholders.via,
+              viaNames: names.join(", ")
+            }));
+          }
+          if (!indirect) {
+            help.append("div").html(_t.html("restriction.help.toggle", { turn: { html: nextText.trim() } }));
+          }
+          highlightPathsFrom(null);
+          var alongIDs = datum2.path.slice();
+          surface.selectAll(utilEntitySelector(alongIDs)).classed("related", true).classed("allow", klass === "allow").classed("restrict", klass === "restrict").classed("only", klass === "only");
+        } else {
+          highlightPathsFrom(null);
+          if (_fromWayID) {
+            help.append("div").html(_t.html("restriction.help.from_name", {
+              from: placeholders.from,
+              fromName: displayName(_fromWayID, vgraph)
+            }));
+          } else {
+            help.append("div").html(_t.html("restriction.help.select_from", {
+              from: placeholders.from
+            }));
+          }
+        }
+      }
+    }
+    function displayMaxDistance(maxDist) {
+      return (selection2) => {
+        var isImperial = !_mainLocalizer.usesMetric();
+        var opts;
+        if (isImperial) {
+          var distToFeet = {
+            // imprecise conversion for prettier display
+            20: 70,
+            25: 85,
+            30: 100,
+            35: 115,
+            40: 130,
+            45: 145,
+            50: 160
+          }[maxDist];
+          opts = { distance: _t("units.feet", { quantity: distToFeet }) };
+        } else {
+          opts = { distance: _t("units.meters", { quantity: maxDist }) };
+        }
+        return selection2.html("").call(_t.append("restriction.controls.distance_up_to", opts));
+      };
+    }
+    function displayMaxVia(maxVia) {
+      return (selection2) => {
+        selection2 = selection2.html("");
+        return maxVia === 0 ? selection2.call(_t.append("restriction.controls.via_node_only")) : maxVia === 1 ? selection2.call(_t.append("restriction.controls.via_up_to_one")) : selection2.call(_t.append("restriction.controls.via_up_to_two"));
+      };
+    }
+    function displayName(entityID, graph) {
+      var entity = graph.entity(entityID);
+      var name = utilDisplayName(entity) || "";
+      var matched = _mainPresetIndex.match(entity, graph);
+      var type2 = matched && matched.name() || utilDisplayType(entity.id);
+      return name || type2;
+    }
+    restrictions.entityIDs = function(val) {
+      _intersection = null;
+      _fromWayID = null;
+      _oldTurns = null;
+      _vertexID = val[0];
+    };
+    restrictions.tags = function() {
+    };
+    restrictions.focus = function() {
+    };
+    restrictions.off = function(selection2) {
+      if (!_initialized3) return;
+      selection2.selectAll(".surface").call(breathe.off).on("click.restrictions", null).on("mouseover.restrictions", null);
+      select_default2(window).on("resize.restrictions", null);
+    };
+    return utilRebind(restrictions, dispatch14, "on");
+  }
+  uiFieldRestrictions.supportsMultiselection = false;
+
+  // modules/ui/fields/textarea.js
+  function uiFieldTextarea(field, context) {
+    var dispatch14 = dispatch_default("change");
+    var input = select_default2(null);
+    var _lengthIndicator = uiLengthIndicator(context.maxCharsForTagValue()).silent(field.usage === "changeset" && field.key === "comment");
+    var _tags;
+    function textarea(selection2) {
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).style("position", "relative").merge(wrap2);
+      input = wrap2.selectAll("textarea").data([0]);
+      input = input.enter().append("textarea").attr("id", field.domId).call(utilNoAuto).on("input", change(true)).on("blur", change()).on("change", change()).merge(input);
+      wrap2.call(_lengthIndicator);
+      function change(onInput) {
+        return function() {
+          var val = utilGetSetValue(input);
+          if (!onInput) val = context.cleanTagValue(val);
+          if (!val && Array.isArray(_tags[field.key])) return;
+          var t2 = {};
+          t2[field.key] = val || void 0;
+          dispatch14.call("change", this, t2, onInput);
+        };
+      }
+    }
+    textarea.tags = function(tags) {
+      _tags = tags;
+      var isMixed = Array.isArray(tags[field.key]);
+      utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : "").attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : void 0).attr("placeholder", isMixed ? _t("inspector.multiple_values") : field.placeholder() || _t("inspector.unknown")).classed("mixed", isMixed);
+      if (!isMixed) {
+        _lengthIndicator.update(tags[field.key]);
+      }
+    };
+    textarea.focus = function() {
+      input.node().focus();
+    };
+    return utilRebind(textarea, dispatch14, "on");
+  }
+
+  // modules/ui/fields/wikidata.js
+  function uiFieldWikidata(field, context) {
+    var wikidata = services.wikidata;
+    var dispatch14 = dispatch_default("change");
+    var _selection = select_default2(null);
+    var _searchInput = select_default2(null);
+    var _qid = null;
+    var _wikidataEntity = null;
+    var _wikiURL = "";
+    var _entityIDs = [];
+    var _wikipediaKey = field.keys && field.keys.find(function(key) {
+      return key.includes("wikipedia");
+    });
+    var _hintKey = field.key === "wikidata" ? "name" : field.key.split(":")[0];
+    var combobox = uiCombobox(context, "combo-" + field.safeid).caseSensitive(true).minItems(1);
+    function wiki(selection2) {
+      _selection = selection2;
+      var wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-" + field.type).merge(wrap2);
+      var list2 = wrap2.selectAll("ul").data([0]);
+      list2 = list2.enter().append("ul").attr("class", "rows").merge(list2);
+      var searchRow = list2.selectAll("li.wikidata-search").data([0]);
+      var searchRowEnter = searchRow.enter().append("li").attr("class", "wikidata-search");
+      searchRowEnter.append("input").attr("type", "text").attr("id", field.domId).style("flex", "1").call(utilNoAuto).on("focus", function() {
+        var node = select_default2(this).node();
+        node.setSelectionRange(0, node.value.length);
+      }).on("blur", function() {
+        setLabelForEntity();
+      }).call(combobox.fetcher(fetchWikidataItems));
+      combobox.on("accept", function(d2) {
+        if (d2) {
+          _qid = d2.id;
+          change();
+        }
+      }).on("cancel", function() {
+        setLabelForEntity();
+      });
+      searchRowEnter.append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain: "wikidata.org" })).call(svgIcon("#iD-icon-out-link")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        if (_wikiURL) window.open(_wikiURL, "_blank");
+      });
+      searchRow = searchRow.merge(searchRowEnter);
+      _searchInput = searchRow.select("input");
+      var wikidataProperties = ["description", "identifier"];
+      var items = list2.selectAll("li.labeled-input").data(wikidataProperties);
+      var enter = items.enter().append("li").attr("class", function(d2) {
+        return "labeled-input preset-wikidata-" + d2;
+      });
+      enter.append("div").attr("class", "label").html(function(d2) {
+        return _t.html("wikidata." + d2);
+      });
+      enter.append("input").attr("type", "text").call(utilNoAuto).classed("disabled", "true").attr("readonly", "true");
+      enter.append("button").attr("class", "form-field-button").attr("title", _t("icons.copy")).call(svgIcon("#iD-operation-copy")).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        select_default2(this.parentNode).select("input").node().select();
+        document.execCommand("copy");
+      });
+    }
+    function fetchWikidataItems(q2, callback) {
+      if (!q2 && _hintKey) {
+        for (var i3 in _entityIDs) {
+          var entity = context.hasEntity(_entityIDs[i3]);
+          if (entity.tags[_hintKey]) {
+            q2 = entity.tags[_hintKey];
+            break;
+          }
+        }
+      }
+      wikidata.itemsForSearchQuery(q2, function(err, data) {
+        if (err) {
+          if (err !== "No query") console.error(err);
+          return;
+        }
+        var result = data.map(function(item) {
+          return {
+            id: item.id,
+            value: item.display.label.value + " (" + item.id + ")",
+            display: (selection2) => selection2.append("span").attr("class", "localized-text").attr("lang", item.display.label.language).text(item.display.label.value),
+            title: item.display.description && item.display.description.value,
+            terms: item.aliases
+          };
+        });
+        if (callback) callback(result);
+      });
+    }
+    function change() {
+      var syncTags = {};
+      syncTags[field.key] = _qid;
+      dispatch14.call("change", this, syncTags);
+      var initGraph = context.graph();
+      var initEntityIDs = _entityIDs;
+      wikidata.entityByQID(_qid, function(err, entity) {
+        if (err) return;
+        if (context.graph() !== initGraph) return;
+        if (!entity.sitelinks) return;
+        var langs = wikidata.languagesToQuery();
+        ["labels", "descriptions"].forEach(function(key) {
+          if (!entity[key]) return;
+          var valueLangs = Object.keys(entity[key]);
+          if (valueLangs.length === 0) return;
+          var valueLang = valueLangs[0];
+          if (langs.indexOf(valueLang) === -1) {
+            langs.push(valueLang);
+          }
+        });
+        var newWikipediaValue;
+        if (_wikipediaKey) {
+          var foundPreferred;
+          for (var i3 in langs) {
+            var lang = langs[i3];
+            var siteID = lang.replace("-", "_") + "wiki";
+            if (entity.sitelinks[siteID]) {
+              foundPreferred = true;
+              newWikipediaValue = lang + ":" + entity.sitelinks[siteID].title;
+              break;
+            }
+          }
+          if (!foundPreferred) {
+            var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function(site) {
+              return site.endsWith("wiki");
+            });
+            if (wikiSiteKeys.length === 0) {
+              newWikipediaValue = null;
+            } else {
+              var wikiLang = wikiSiteKeys[0].slice(0, -4).replace("_", "-");
+              var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
+              newWikipediaValue = wikiLang + ":" + wikiTitle;
+            }
+          }
+        }
+        if (newWikipediaValue) {
+          newWikipediaValue = context.cleanTagValue(newWikipediaValue);
+        }
+        if (typeof newWikipediaValue === "undefined") return;
+        var actions = initEntityIDs.map(function(entityID) {
+          var entity2 = context.hasEntity(entityID);
+          if (!entity2) return null;
+          var currTags = Object.assign({}, entity2.tags);
+          if (newWikipediaValue === null) {
+            if (!currTags[_wikipediaKey]) return null;
+            delete currTags[_wikipediaKey];
+          } else {
+            currTags[_wikipediaKey] = newWikipediaValue;
+          }
+          return actionChangeTags(entityID, currTags);
+        }).filter(Boolean);
+        if (!actions.length) return;
+        context.overwrite(
+          function actionUpdateWikipediaTags(graph) {
+            actions.forEach(function(action) {
+              graph = action(graph);
+            });
+            return graph;
+          },
+          context.history().undoAnnotation()
+        );
+      });
+    }
+    function setLabelForEntity() {
+      var label = "";
+      if (_wikidataEntity) {
+        label = entityPropertyForDisplay(_wikidataEntity, "labels");
+        if (label.length === 0) {
+          label = _wikidataEntity.id.toString();
+        }
+      }
+      utilGetSetValue(_searchInput, label);
+    }
+    wiki.tags = function(tags) {
+      var isMixed = Array.isArray(tags[field.key]);
+      _searchInput.attr("title", isMixed ? tags[field.key].filter(Boolean).join("\n") : null).attr("placeholder", isMixed ? _t("inspector.multiple_values") : "").classed("mixed", isMixed);
+      _qid = typeof tags[field.key] === "string" && tags[field.key] || "";
+      if (!/^Q[0-9]*$/.test(_qid)) {
+        unrecognized();
+        return;
+      }
+      _wikiURL = "https://wikidata.org/wiki/" + _qid;
+      wikidata.entityByQID(_qid, function(err, entity) {
+        if (err) {
+          unrecognized();
+          return;
+        }
+        _wikidataEntity = entity;
+        setLabelForEntity();
+        var description = entityPropertyForDisplay(entity, "descriptions");
+        _selection.select("button.wiki-link").classed("disabled", false);
+        _selection.select(".preset-wikidata-description").style("display", function() {
+          return description.length > 0 ? "flex" : "none";
+        }).select("input").attr("value", description);
+        _selection.select(".preset-wikidata-identifier").style("display", function() {
+          return entity.id ? "flex" : "none";
+        }).select("input").attr("value", entity.id);
+      });
+      function unrecognized() {
+        _wikidataEntity = null;
+        setLabelForEntity();
+        _selection.select(".preset-wikidata-description").style("display", "none");
+        _selection.select(".preset-wikidata-identifier").style("display", "none");
+        _selection.select("button.wiki-link").classed("disabled", true);
+        if (_qid && _qid !== "") {
+          _wikiURL = "https://wikidata.org/wiki/Special:Search?search=" + _qid;
+        } else {
+          _wikiURL = "";
+        }
+      }
+    };
+    function entityPropertyForDisplay(wikidataEntity, propKey) {
+      if (!wikidataEntity[propKey]) return "";
+      var propObj = wikidataEntity[propKey];
+      var langKeys = Object.keys(propObj);
+      if (langKeys.length === 0) return "";
+      var langs = wikidata.languagesToQuery();
+      for (var i3 in langs) {
+        var lang = langs[i3];
+        var valueObj = propObj[lang];
+        if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
+      }
+      return propObj[langKeys[0]].value;
+    }
+    wiki.entityIDs = function(val) {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return wiki;
+    };
+    wiki.focus = function() {
+      _searchInput.node().focus();
+    };
+    return utilRebind(wiki, dispatch14, "on");
+  }
+
+  // modules/ui/fields/wikipedia.js
+  function uiFieldWikipedia(field, context) {
+    const scheme = "https://";
+    const domain = "wikipedia.org";
+    const dispatch14 = dispatch_default("change");
+    const wikipedia = services.wikipedia;
+    const wikidata = services.wikidata;
+    let _langInput = select_default2(null);
+    let _titleInput = select_default2(null);
+    let _wikiURL = "";
+    let _entityIDs;
+    let _tags;
+    let _dataWikipedia = [];
+    _mainFileFetcher.get("wmf_sitematrix").then((d2) => {
+      _dataWikipedia = d2;
+      if (_tags) updateForTags(_tags);
+    }).catch(() => {
+    });
+    const langCombo = uiCombobox(context, "wikipedia-lang").fetcher((value, callback) => {
+      const v2 = value.toLowerCase();
+      callback(
+        _dataWikipedia.filter((d2) => {
+          return d2[0].toLowerCase().indexOf(v2) >= 0 || d2[1].toLowerCase().indexOf(v2) >= 0 || d2[2].toLowerCase().indexOf(v2) >= 0;
+        }).map((d2) => ({ value: d2[1] }))
+      );
+    });
+    const titleCombo = uiCombobox(context, "wikipedia-title").fetcher((value, callback) => {
+      if (!value) {
+        value = "";
+        for (let i3 in _entityIDs) {
+          let entity = context.hasEntity(_entityIDs[i3]);
+          if (entity.tags.name) {
+            value = entity.tags.name;
+            break;
+          }
+        }
+      }
+      const searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
+      searchfn(language()[2], value, (query, data) => {
+        callback(data.map((d2) => ({ value: d2 })));
+      });
+    });
+    function wiki(selection2) {
+      let wrap2 = selection2.selectAll(".form-field-input-wrap").data([0]);
+      wrap2 = wrap2.enter().append("div").attr("class", "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap2);
+      let langContainer = wrap2.selectAll(".wiki-lang-container").data([0]);
+      langContainer = langContainer.enter().append("div").attr("class", "wiki-lang-container").merge(langContainer);
+      _langInput = langContainer.selectAll("input.wiki-lang").data([0]);
+      _langInput = _langInput.enter().append("input").attr("type", "text").attr("class", "wiki-lang").attr("placeholder", _t("translate.localized_translation_language")).call(utilNoAuto).call(langCombo).merge(_langInput);
+      _langInput.on("blur", changeLang).on("change", changeLang);
+      let titleContainer = wrap2.selectAll(".wiki-title-container").data([0]);
+      titleContainer = titleContainer.enter().append("div").attr("class", "wiki-title-container").merge(titleContainer);
+      _titleInput = titleContainer.selectAll("input.wiki-title").data([0]);
+      _titleInput = _titleInput.enter().append("input").attr("type", "text").attr("class", "wiki-title").attr("id", field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
+      _titleInput.on("blur", function() {
+        change(true);
+      }).on("change", function() {
+        change(false);
+      });
+      let link3 = titleContainer.selectAll(".wiki-link").data([0]);
+      link3 = link3.enter().append("button").attr("class", "form-field-button wiki-link").attr("title", _t("icons.view_on", { domain })).call(svgIcon("#iD-icon-out-link")).merge(link3);
+      link3.on("click", (d3_event) => {
+        d3_event.preventDefault();
+        if (_wikiURL) window.open(_wikiURL, "_blank");
+      });
+    }
+    function defaultLanguageInfo(skipEnglishFallback) {
+      const langCode = _mainLocalizer.languageCode().toLowerCase();
+      for (let i3 in _dataWikipedia) {
+        let d2 = _dataWikipedia[i3];
+        if (d2[2] === langCode) return d2;
+      }
+      return skipEnglishFallback ? ["", "", ""] : ["English", "English", "en"];
+    }
+    function language(skipEnglishFallback) {
+      const value = utilGetSetValue(_langInput).toLowerCase();
+      for (let i3 in _dataWikipedia) {
+        let d2 = _dataWikipedia[i3];
+        if (d2[0].toLowerCase() === value || d2[1].toLowerCase() === value || d2[2] === value) return d2;
+      }
+      return defaultLanguageInfo(skipEnglishFallback);
+    }
+    function changeLang() {
+      utilGetSetValue(_langInput, language()[1]);
+      change(true);
+    }
+    function change(skipWikidata) {
+      let value = utilGetSetValue(_titleInput);
+      const m2 = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
+      const langInfo = m2 && _dataWikipedia.find((d2) => m2[1] === d2[2]);
+      let syncTags = {};
+      if (langInfo) {
+        const nativeLangName = langInfo[1];
+        value = decodeURIComponent(m2[2]).replace(/_/g, " ");
+        if (m2[3]) {
+          let anchor;
+          anchor = decodeURIComponent(m2[3]);
+          value += "#" + anchor.replace(/_/g, " ");
+        }
+        value = value.slice(0, 1).toUpperCase() + value.slice(1);
+        utilGetSetValue(_langInput, nativeLangName);
+        utilGetSetValue(_titleInput, value);
+      }
+      if (value) {
+        syncTags.wikipedia = context.cleanTagValue(language()[2] + ":" + value);
+      } else {
+        syncTags.wikipedia = void 0;
+      }
+      dispatch14.call("change", this, syncTags);
+      if (skipWikidata || !value || !language()[2]) return;
+      const initGraph = context.graph();
+      const initEntityIDs = _entityIDs;
+      wikidata.itemsByTitle(language()[2], value, (err, data) => {
+        if (err || !data || !Object.keys(data).length) return;
+        if (context.graph() !== initGraph) return;
+        const qids = Object.keys(data);
+        const value2 = qids && qids.find((id2) => id2.match(/^Q\d+$/));
+        let actions = initEntityIDs.map((entityID) => {
+          let entity = context.entity(entityID).tags;
+          let currTags = Object.assign({}, entity);
+          if (currTags.wikidata !== value2) {
+            currTags.wikidata = value2;
+            return actionChangeTags(entityID, currTags);
+          }
+          return null;
+        }).filter(Boolean);
+        if (!actions.length) return;
+        context.overwrite(
+          function actionUpdateWikidataTags(graph) {
+            actions.forEach(function(action) {
+              graph = action(graph);
+            });
+            return graph;
+          },
+          context.history().undoAnnotation()
+        );
+      });
+    }
+    wiki.tags = (tags) => {
+      _tags = tags;
+      updateForTags(tags);
+    };
+    function updateForTags(tags) {
+      const value = typeof tags[field.key] === "string" ? tags[field.key] : "";
+      const m2 = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
+      const tagLang = m2 && m2[1];
+      const tagArticleTitle = m2 && m2[2];
+      let anchor = m2 && m2[3];
+      const tagLangInfo = tagLang && _dataWikipedia.find((d2) => tagLang === d2[2]);
+      if (tagLangInfo) {
+        const nativeLangName = tagLangInfo[1];
+        utilGetSetValue(_langInput, nativeLangName);
+        utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? "#" + anchor : ""));
+        _wikiURL = "".concat(scheme).concat(tagLang, ".").concat(domain, "/wiki/").concat(wiki.encodePath(tagArticleTitle, anchor));
+      } else {
+        utilGetSetValue(_titleInput, value);
+        if (value && value !== "") {
+          utilGetSetValue(_langInput, "");
+          const defaultLangInfo = defaultLanguageInfo();
+          _wikiURL = "".concat(scheme).concat(defaultLangInfo[2], ".").concat(domain, "/w/index.php?fulltext=1&search=").concat(value);
+        } else {
+          const shownOrDefaultLangInfo = language(
+            true
+            /* skipEnglishFallback */
+          );
+          utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
+          _wikiURL = "";
+        }
+      }
+    }
+    wiki.encodePath = (tagArticleTitle, anchor) => {
+      const underscoredTitle = tagArticleTitle.replace(/ /g, "_");
+      const uriEncodedUnderscoredTitle = encodeURIComponent(underscoredTitle);
+      const uriEncodedAnchorFragment = wiki.encodeURIAnchorFragment(anchor);
+      return "".concat(uriEncodedUnderscoredTitle).concat(uriEncodedAnchorFragment);
+    };
+    wiki.encodeURIAnchorFragment = (anchor) => {
+      if (!anchor) return "";
+      const underscoredAnchor = anchor.replace(/ /g, "_");
+      return "#" + encodeURIComponent(underscoredAnchor);
+    };
+    wiki.entityIDs = (val) => {
+      if (!arguments.length) return _entityIDs;
+      _entityIDs = val;
+      return wiki;
+    };
+    wiki.focus = () => {
+      _titleInput.node().focus();
+    };
+    return utilRebind(wiki, dispatch14, "on");
+  }
+  uiFieldWikipedia.supportsMultiselection = false;
+
+  // modules/ui/fields/index.js
+  var uiFields = {
+    access: uiFieldAccess,
+    address: uiFieldAddress,
+    check: uiFieldCheck,
+    colour: uiFieldText,
+    combo: uiFieldCombo,
+    cycleway: uiFieldDirectionalCombo,
+    date: uiFieldText,
+    defaultCheck: uiFieldCheck,
+    directionalCombo: uiFieldDirectionalCombo,
+    email: uiFieldText,
+    identifier: uiFieldText,
+    lanes: uiFieldLanes,
+    localized: uiFieldLocalized,
+    roadheight: uiFieldRoadheight,
+    roadspeed: uiFieldRoadspeed,
+    manyCombo: uiFieldCombo,
+    multiCombo: uiFieldCombo,
+    networkCombo: uiFieldCombo,
+    number: uiFieldText,
+    onewayCheck: uiFieldCheck,
+    radio: uiFieldRadio,
+    restrictions: uiFieldRestrictions,
+    semiCombo: uiFieldCombo,
+    structureRadio: uiFieldRadio,
+    tel: uiFieldText,
+    text: uiFieldText,
+    textarea: uiFieldTextarea,
+    typeCombo: uiFieldCombo,
+    url: uiFieldText,
+    wikidata: uiFieldWikidata,
+    wikipedia: uiFieldWikipedia
+  };
+
+  // modules/ui/field.js
+  function uiField(context, presetField2, entityIDs, options2) {
+    options2 = Object.assign({
+      show: true,
+      wrap: true,
+      remove: true,
+      revert: true,
+      info: true
+    }, options2);
+    var dispatch14 = dispatch_default("change", "revert");
+    var field = Object.assign({}, presetField2);
+    field.domId = utilUniqueDomId("form-field-" + field.safeid);
+    var _show = options2.show;
+    var _state = "";
+    var _tags = {};
+    var _entityExtent;
+    if (entityIDs && entityIDs.length) {
+      _entityExtent = entityIDs.reduce(function(extent, entityID) {
+        var entity = context.graph().entity(entityID);
+        return extent.extend(entity.extent(context.graph()));
+      }, geoExtent());
+    }
+    var _locked = false;
+    var _lockedTip = uiTooltip().title(() => _t.append("inspector.lock.suggestion", { label: field.title })).placement("bottom");
+    if (_show && !field.impl) {
+      createField();
+    }
+    function createField() {
+      field.impl = uiFields[field.type](field, context).on("change", function(t2, onInput) {
+        dispatch14.call("change", field, t2, onInput);
+      });
+      if (entityIDs) {
+        field.entityIDs = entityIDs;
+        if (field.impl.entityIDs) {
+          field.impl.entityIDs(entityIDs);
+        }
+      }
+    }
+    function allKeys() {
+      let keys2 = field.keys || [field.key];
+      if (field.type === "directionalCombo" && field.key) {
+        keys2 = keys2.concat(field.key);
+      }
+      return keys2;
+    }
+    function isModified() {
+      if (!entityIDs || !entityIDs.length) return false;
+      return entityIDs.some(function(entityID) {
+        var original = context.graph().base().entities[entityID];
+        var latest = context.graph().entity(entityID);
+        return allKeys().some(function(key) {
+          return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
+        });
+      });
+    }
+    function tagsContainFieldKey() {
+      return allKeys().some(function(key) {
+        if (field.type === "multiCombo") {
+          for (var tagKey in _tags) {
+            if (tagKey.indexOf(key) === 0) {
+              return true;
+            }
+          }
+          return false;
+        }
+        if (field.type === "localized") {
+          for (let tagKey2 in _tags) {
+            let match = tagKey2.match(LANGUAGE_SUFFIX_REGEX);
+            if (match && match[1] === field.key && match[2]) {
+              return true;
+            }
+          }
+        }
+        return _tags[key] !== void 0;
+      });
+    }
+    function revert(d3_event, d2) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
+      if (!entityIDs || _locked) return;
+      dispatch14.call("revert", d2, allKeys());
+    }
+    function remove2(d3_event, d2) {
+      d3_event.stopPropagation();
+      d3_event.preventDefault();
+      if (_locked) return;
+      var t2 = {};
+      allKeys().forEach(function(key) {
+        t2[key] = void 0;
+      });
+      dispatch14.call("change", d2, t2);
+    }
+    field.render = function(selection2) {
+      var container = selection2.selectAll(".form-field").data([field]);
+      var enter = container.enter().append("div").attr("class", function(d2) {
+        return "form-field form-field-" + d2.safeid;
+      }).classed("nowrap", !options2.wrap);
+      if (options2.wrap) {
+        var labelEnter = enter.append("label").attr("class", "field-label").attr("for", function(d2) {
+          return d2.domId;
+        });
+        var textEnter = labelEnter.append("span").attr("class", "label-text");
+        textEnter.append("span").attr("class", "label-textvalue").each(function(d2) {
+          d2.label()(select_default2(this));
+        });
+        textEnter.append("span").attr("class", "label-textannotation");
+        if (options2.remove) {
+          labelEnter.append("button").attr("class", "remove-icon").attr("title", _t("icons.remove")).call(svgIcon("#iD-operation-delete"));
+        }
+        if (options2.revert) {
+          labelEnter.append("button").attr("class", "modified-icon").attr("title", _t("icons.undo")).call(svgIcon(_mainLocalizer.textDirection() === "rtl" ? "#iD-icon-redo" : "#iD-icon-undo"));
+        }
+      }
+      container = container.merge(enter);
+      container.select(".field-label > .remove-icon").on("click", remove2);
+      container.select(".field-label > .modified-icon").on("click", revert);
+      container.each(function(d2) {
+        var selection3 = select_default2(this);
+        if (!d2.impl) {
+          createField();
+        }
+        var reference, help;
+        if (options2.wrap && field.type === "restrictions") {
+          help = uiFieldHelp(context, "restrictions");
+        }
+        if (options2.wrap && options2.info) {
+          var referenceKey = d2.key || "";
+          if (d2.type === "multiCombo") {
+            referenceKey = referenceKey.replace(/:$/, "");
+          }
+          var referenceOptions = d2.reference || {
+            key: referenceKey,
+            value: _tags[referenceKey]
+          };
+          reference = uiTagReference(referenceOptions, context);
+          if (_state === "hover") {
+            reference.showing(false);
+          }
+        }
+        selection3.call(d2.impl);
+        if (help) {
+          selection3.call(help.body).select(".field-label").call(help.button);
+        }
+        if (reference) {
+          selection3.call(reference.body).select(".field-label").call(reference.button);
+        }
+        d2.impl.tags(_tags);
+      });
+      container.classed("locked", _locked).classed("modified", isModified()).classed("present", tagsContainFieldKey());
+      var annotation = container.selectAll(".field-label .label-textannotation");
+      var icon2 = annotation.selectAll(".icon").data(_locked ? [0] : []);
+      icon2.exit().remove();
+      icon2.enter().append("svg").attr("class", "icon").append("use").attr("xlink:href", "#fas-lock");
+      container.call(_locked ? _lockedTip : _lockedTip.destroy);
+    };
+    field.state = function(val) {
+      if (!arguments.length) return _state;
+      _state = val;
+      return field;
+    };
+    field.tags = function(val) {
+      if (!arguments.length) return _tags;
+      _tags = val;
+      if (tagsContainFieldKey() && !_show) {
+        _show = true;
+        if (!field.impl) {
+          createField();
+        }
+      }
+      return field;
+    };
+    field.locked = function(val) {
+      if (!arguments.length) return _locked;
+      _locked = val;
+      return field;
+    };
+    field.show = function() {
+      _show = true;
+      if (!field.impl) {
+        createField();
+      }
+      if (field.default && field.key && _tags[field.key] !== field.default) {
+        var t2 = {};
+        t2[field.key] = field.default;
+        dispatch14.call("change", this, t2);
+      }
+    };
+    field.isShown = function() {
+      return _show;
+    };
+    field.isAllowed = function() {
+      if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
+      if (field.geometry && !entityIDs.every(function(entityID) {
+        return field.matchGeometry(context.graph().geometry(entityID));
+      })) return false;
+      if (entityIDs && _entityExtent && field.locationSetID) {
+        var validHere = _sharedLocationManager.locationSetsAt(_entityExtent.center());
+        if (!validHere[field.locationSetID]) return false;
+      }
+      var prerequisiteTag = field.prerequisiteTag;
+      if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
+      prerequisiteTag) {
+        if (!entityIDs.every(function(entityID) {
+          var entity = context.graph().entity(entityID);
+          if (prerequisiteTag.key) {
+            var value = entity.tags[prerequisiteTag.key];
+            if (!value) return false;
+            if (prerequisiteTag.valueNot) {
+              return prerequisiteTag.valueNot !== value;
+            }
+            if (prerequisiteTag.value) {
+              return prerequisiteTag.value === value;
+            }
+          } else if (prerequisiteTag.keyNot) {
+            if (entity.tags[prerequisiteTag.keyNot]) return false;
+          }
+          return true;
+        })) return false;
+      }
+      return true;
+    };
+    field.focus = function() {
+      if (field.impl) {
+        field.impl.focus();
+      }
+    };
+    return utilRebind(field, dispatch14, "on");
+  }
+
+  // modules/ui/changeset_editor.js
+  function uiChangesetEditor(context) {
+    var dispatch14 = dispatch_default("change");
+    var formFields = uiFormFields(context);
+    var commentCombo = uiCombobox(context, "comment").caseSensitive(true);
+    var _fieldsArr;
+    var _tags;
+    var _changesetID;
+    function changesetEditor(selection2) {
+      render(selection2);
+    }
+    function render(selection2) {
+      var initial = false;
+      if (!_fieldsArr) {
+        initial = true;
+        var presets = _mainPresetIndex;
+        _fieldsArr = [
+          uiField(context, presets.field("comment"), null, { show: true, revert: false }),
+          uiField(context, presets.field("source"), null, { show: true, revert: false }),
+          uiField(context, presets.field("hashtags"), null, { show: false, revert: false })
+        ];
+        _fieldsArr.forEach(function(field) {
+          field.on("change", function(t2, onInput) {
+            dispatch14.call("change", field, void 0, t2, onInput);
+          });
+        });
+      }
+      _fieldsArr.forEach(function(field) {
+        field.tags(_tags);
+      });
+      selection2.call(formFields.fieldsArr(_fieldsArr));
+      if (initial) {
+        var commentField = selection2.select(".form-field-comment textarea");
+        var commentNode = commentField.node();
+        if (commentNode) {
+          commentNode.focus();
+          commentNode.select();
+        }
+        utilTriggerEvent(commentField, "blur");
+        var osm = context.connection();
+        if (osm) {
+          osm.userChangesets(function(err, changesets) {
+            if (err) return;
+            var comments = changesets.map(function(changeset) {
+              var comment = changeset.tags.comment;
+              return comment ? { title: comment, value: comment } : null;
+            }).filter(Boolean);
+            commentField.call(
+              commentCombo.data(utilArrayUniqBy(comments, "title"))
+            );
+          });
+        }
+      }
+      const warnings = [];
+      if (_tags.comment.match(/google/i)) {
+        warnings.push({
+          id: 'contains "google"',
+          msg: _t.append("commit.google_warning"),
+          link: _t("commit.google_warning_link")
+        });
+      }
+      const maxChars = context.maxCharsForTagValue();
+      const strLen = utilUnicodeCharsCount(utilCleanOsmString(_tags.comment, Number.POSITIVE_INFINITY));
+      if (strLen > maxChars || false) {
+        warnings.push({
+          id: "message too long",
+          msg: _t.append("commit.changeset_comment_length_warning", { maxChars })
+        });
+      }
+      var commentWarning = selection2.select(".form-field-comment").selectAll(".comment-warning").data(warnings, (d2) => d2.id);
+      commentWarning.exit().transition().duration(200).style("opacity", 0).remove();
+      var commentEnter = commentWarning.enter().insert("div", ".comment-warning").attr("class", "comment-warning field-warning").style("opacity", 0);
+      commentEnter.call(svgIcon("#iD-icon-alert", "inline")).append("span");
+      commentEnter.transition().duration(200).style("opacity", 1);
+      commentWarning.merge(commentEnter).selectAll("div > span").text("").each(function(d2) {
+        let selection3 = select_default2(this);
+        if (d2.link) {
+          selection3 = selection3.append("a").attr("target", "_blank").attr("href", d2.link);
+        }
+        selection3.call(d2.msg);
+      });
+    }
+    changesetEditor.tags = function(_2) {
+      if (!arguments.length) return _tags;
+      _tags = _2;
+      return changesetEditor;
+    };
+    changesetEditor.changesetID = function(_2) {
+      if (!arguments.length) return _changesetID;
+      if (_changesetID === _2) return changesetEditor;
+      _changesetID = _2;
+      _fieldsArr = null;
+      return changesetEditor;
+    };
+    return utilRebind(changesetEditor, dispatch14, "on");
+  }
+
+  // modules/ui/sections/changes.js
+  function uiSectionChanges(context) {
+    var _discardTags = {};
+    _mainFileFetcher.get("discarded").then(function(d2) {
+      _discardTags = d2;
+    }).catch(function() {
+    });
+    var section = uiSection("changes-list", context).label(function() {
+      var history = context.history();
+      var summary = history.difference().summary();
+      return _t.append("inspector.title_count", { title: _t("commit.changes"), count: summary.length });
+    }).disclosureContent(renderDisclosureContent);
+    function renderDisclosureContent(selection2) {
+      var history = context.history();
+      var summary = history.difference().summary();
+      var container = selection2.selectAll(".commit-section").data([0]);
+      var containerEnter = container.enter().append("div").attr("class", "commit-section");
+      containerEnter.append("ul").attr("class", "changeset-list");
+      container = containerEnter.merge(container);
+      var items = container.select("ul").selectAll("li").data(summary);
+      var itemsEnter = items.enter().append("li").attr("class", "change-item");
+      var buttons = itemsEnter.append("button").on("mouseover", mouseover).on("mouseout", mouseout).on("click", click);
+      buttons.each(function(d2) {
+        select_default2(this).call(svgIcon("#iD-icon-" + d2.entity.geometry(d2.graph), "pre-text " + d2.changeType));
+      });
+      buttons.append("span").attr("class", "change-type").html(function(d2) {
+        return _t.html("commit." + d2.changeType) + " ";
+      });
+      buttons.append("strong").attr("class", "entity-type").text(function(d2) {
+        var matched = _mainPresetIndex.match(d2.entity, d2.graph);
+        return matched && matched.name() || utilDisplayType(d2.entity.id);
+      });
+      buttons.append("span").attr("class", "entity-name").text(function(d2) {
+        var name = utilDisplayName(d2.entity) || "", string = "";
+        if (name !== "") {
+          string += ":";
+        }
+        return string += " " + name;
+      });
+      items = itemsEnter.merge(items);
+      var changeset = new osmChangeset().update({ id: void 0 });
+      var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
+      delete changeset.id;
+      var data = JXON.stringify(changeset.osmChangeJXON(changes));
+      var blob = new Blob([data], { type: "text/xml;charset=utf-8;" });
+      var fileName = "changes.osc";
+      var linkEnter = container.selectAll(".download-changes").data([0]).enter().append("a").attr("class", "download-changes");
+      linkEnter.attr("href", window.URL.createObjectURL(blob)).attr("download", fileName);
+      linkEnter.call(svgIcon("#iD-icon-load", "inline")).append("span").call(_t.append("commit.download_changes"));
+      function mouseover(d2) {
+        if (d2.entity) {
+          context.surface().selectAll(
+            utilEntityOrMemberSelector([d2.entity.id], context.graph())
+          ).classed("hover", true);
+        }
+      }
+      function mouseout() {
+        context.surface().selectAll(".hover").classed("hover", false);
+      }
+      function click(d3_event, change) {
+        if (change.changeType !== "deleted") {
+          var entity = change.entity;
+          context.map().zoomToEase(entity);
+          context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed("hover", true);
+        }
+      }
+    }
+    return section;
+  }
+
+  // modules/ui/commit.js
+  var readOnlyTags = [
+    /^changesets_count$/,
+    /^created_by$/,
+    /^ideditor:/,
+    /^imagery_used$/,
+    /^host$/,
+    /^locale$/,
+    /^warnings:/,
+    /^resolved:/,
+    /^closed:note$/,
+    /^closed:keepright$/,
+    /^closed:osmose:/
+  ];
+  var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
+  function uiCommit(context) {
+    var dispatch14 = dispatch_default("cancel");
+    var _userDetails2;
+    var _selection;
+    var changesetEditor = uiChangesetEditor(context).on("change", changeTags);
+    var rawTagEditor = uiSectionRawTagEditor("changeset-tag-editor", context).on("change", changeTags).readOnlyTags(readOnlyTags);
+    var commitChanges = uiSectionChanges(context);
+    var commitWarnings = uiCommitWarnings(context);
+    function commit(selection2) {
+      _selection = selection2;
+      if (!context.changeset) initChangeset();
+      loadDerivedChangesetTags();
+      selection2.call(render);
+    }
+    function initChangeset() {
+      var commentDate = +corePreferences("commentDate") || 0;
+      var currDate = Date.now();
+      var cutoff = 2 * 86400 * 1e3;
+      if (commentDate > currDate || currDate - commentDate > cutoff) {
+        corePreferences("comment", null);
+        corePreferences("hashtags", null);
+        corePreferences("source", null);
+      }
+      if (context.defaultChangesetComment()) {
+        corePreferences("comment", context.defaultChangesetComment());
+        corePreferences("commentDate", Date.now());
+      }
+      if (context.defaultChangesetSource()) {
+        corePreferences("source", context.defaultChangesetSource());
+        corePreferences("commentDate", Date.now());
+      }
+      if (context.defaultChangesetHashtags()) {
+        corePreferences("hashtags", context.defaultChangesetHashtags());
+        corePreferences("commentDate", Date.now());
+      }
+      var detected = utilDetect();
+      var tags = {
+        comment: corePreferences("comment") || "",
+        created_by: context.cleanTagValue("iD " + context.version),
+        host: context.cleanTagValue(detected.host),
+        locale: context.cleanTagValue(_mainLocalizer.localeCode())
+      };
+      findHashtags(tags, true);
+      var hashtags = corePreferences("hashtags");
+      if (hashtags) {
+        tags.hashtags = hashtags;
+      }
+      var source = corePreferences("source");
+      if (source) {
+        tags.source = source;
+      }
+      var photoOverlaysUsed = context.history().photoOverlaysUsed();
+      if (photoOverlaysUsed.length) {
+        var sources = (tags.source || "").split(";");
+        if (sources.indexOf("streetlevel imagery") === -1) {
+          sources.push("streetlevel imagery");
+        }
+        photoOverlaysUsed.forEach(function(photoOverlay) {
+          if (sources.indexOf(photoOverlay) === -1) {
+            sources.push(photoOverlay);
+          }
+        });
+        tags.source = context.cleanTagValue(sources.join(";"));
+      }
+      context.changeset = new osmChangeset({ tags });
+    }
+    function loadDerivedChangesetTags() {
+      var osm = context.connection();
+      if (!osm) return;
+      var tags = Object.assign({}, context.changeset.tags);
+      var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(";"));
+      tags.imagery_used = imageryUsed || "None";
+      var osmClosed = osm.getClosedIDs();
+      var itemType;
+      if (osmClosed.length) {
+        tags["closed:note"] = context.cleanTagValue(osmClosed.join(";"));
+      }
+      if (services.keepRight) {
+        var krClosed = services.keepRight.getClosedIDs();
+        if (krClosed.length) {
+          tags["closed:keepright"] = context.cleanTagValue(krClosed.join(";"));
+        }
+      }
+      if (services.osmose) {
+        var osmoseClosed = services.osmose.getClosedCounts();
+        for (itemType in osmoseClosed) {
+          tags["closed:osmose:" + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
+        }
+      }
+      for (var key in tags) {
+        if (key.match(/(^warnings:)|(^resolved:)/)) {
+          delete tags[key];
+        }
+      }
+      function addIssueCounts(issues, prefix) {
+        var issuesByType = utilArrayGroupBy(issues, "type");
+        for (var issueType in issuesByType) {
+          var issuesOfType = issuesByType[issueType];
+          if (issuesOfType[0].subtype) {
+            var issuesBySubtype = utilArrayGroupBy(issuesOfType, "subtype");
+            for (var issueSubtype in issuesBySubtype) {
+              var issuesOfSubtype = issuesBySubtype[issueSubtype];
+              tags[prefix + ":" + issueType + ":" + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
+            }
+          } else {
+            tags[prefix + ":" + issueType] = context.cleanTagValue(issuesOfType.length.toString());
+          }
+        }
+      }
+      var warnings = context.validator().getIssuesBySeverity({ what: "edited", where: "all", includeIgnored: true, includeDisabledRules: true }).warning.filter(function(issue) {
+        return issue.type !== "help_request";
+      });
+      addIssueCounts(warnings, "warnings");
+      var resolvedIssues = context.validator().getResolvedIssues();
+      addIssueCounts(resolvedIssues, "resolved");
+      context.changeset = context.changeset.update({ tags });
+    }
+    function render(selection2) {
+      var osm = context.connection();
+      if (!osm) return;
+      var header = selection2.selectAll(".header").data([0]);
+      var headerTitle = header.enter().append("div").attr("class", "header fillL");
+      headerTitle.append("div").append("h2").call(_t.append("commit.title"));
+      headerTitle.append("button").attr("class", "close").attr("title", _t("icons.close")).on("click", function() {
+        dispatch14.call("cancel", this);
+      }).call(svgIcon("#iD-icon-close"));
+      var body = selection2.selectAll(".body").data([0]);
+      body = body.enter().append("div").attr("class", "body").merge(body);
+      var changesetSection = body.selectAll(".changeset-editor").data([0]);
+      changesetSection = changesetSection.enter().append("div").attr("class", "modal-section changeset-editor").merge(changesetSection);
+      changesetSection.call(
+        changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)
+      );
+      body.call(commitWarnings);
+      var saveSection = body.selectAll(".save-section").data([0]);
+      saveSection = saveSection.enter().append("div").attr("class", "modal-section save-section fillL").merge(saveSection);
+      var prose = saveSection.selectAll(".commit-info").data([0]);
+      if (prose.enter().size()) {
+        _userDetails2 = null;
+      }
+      prose = prose.enter().append("p").attr("class", "commit-info").call(_t.append("commit.upload_explanation")).merge(prose);
+      osm.userDetails(function(err, user) {
+        if (err) return;
+        if (_userDetails2 === user) return;
+        _userDetails2 = user;
+        var userLink = select_default2(document.createElement("div"));
+        if (user.image_url) {
+          userLink.append("img").attr("src", user.image_url).attr("class", "icon pre-text user-icon");
+        }
+        userLink.append("a").attr("class", "user-info").text(user.display_name).attr("href", osm.userURL(user.display_name)).attr("target", "_blank");
+        prose.html(_t.html("commit.upload_explanation_with_user", { user: { html: userLink.html() } }));
+      });
+      var requestReview = saveSection.selectAll(".request-review").data([0]);
+      var requestReviewEnter = requestReview.enter().append("div").attr("class", "request-review");
+      var requestReviewDomId = utilUniqueDomId("commit-input-request-review");
+      var labelEnter = requestReviewEnter.append("label").attr("for", requestReviewDomId);
+      if (!labelEnter.empty()) {
+        labelEnter.call(uiTooltip().title(() => _t.append("commit.request_review_info")).placement("top"));
+      }
+      labelEnter.append("input").attr("type", "checkbox").attr("id", requestReviewDomId);
+      labelEnter.append("span").call(_t.append("commit.request_review"));
+      requestReview = requestReview.merge(requestReviewEnter);
+      var requestReviewInput = requestReview.selectAll("input").property("checked", isReviewRequested(context.changeset.tags)).on("change", toggleRequestReview);
+      var buttonSection = saveSection.selectAll(".buttons").data([0]);
+      var buttonEnter = buttonSection.enter().append("div").attr("class", "buttons fillL");
+      buttonEnter.append("button").attr("class", "secondary-action button cancel-button").append("span").attr("class", "label").call(_t.append("commit.cancel"));
+      var uploadButton = buttonEnter.append("button").attr("class", "action button save-button");
+      uploadButton.append("span").attr("class", "label").call(_t.append("commit.save"));
+      var uploadBlockerTooltipText = getUploadBlockerMessage();
+      buttonSection = buttonSection.merge(buttonEnter);
+      buttonSection.selectAll(".cancel-button").on("click.cancel", function() {
+        dispatch14.call("cancel", this);
+      });
+      buttonSection.selectAll(".save-button").classed("disabled", uploadBlockerTooltipText !== null).on("click.save", function() {
+        if (!select_default2(this).classed("disabled")) {
+          this.blur();
+          for (var key in context.changeset.tags) {
+            if (!key) delete context.changeset.tags[key];
+          }
+          context.uploader().save(context.changeset);
+        }
+      });
+      uiTooltip().destroyAny(buttonSection.selectAll(".save-button"));
+      if (uploadBlockerTooltipText) {
+        buttonSection.selectAll(".save-button").call(uiTooltip().title(() => uploadBlockerTooltipText).placement("top"));
+      }
+      var tagSection = body.selectAll(".tag-section.raw-tag-editor").data([0]);
+      tagSection = tagSection.enter().append("div").attr("class", "modal-section tag-section raw-tag-editor").merge(tagSection);
+      tagSection.call(
+        rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
+      );
+      var changesSection = body.selectAll(".commit-changes-section").data([0]);
+      changesSection = changesSection.enter().append("div").attr("class", "modal-section commit-changes-section").merge(changesSection);
+      changesSection.call(commitChanges.render);
+      function toggleRequestReview() {
+        var rr = requestReviewInput.property("checked");
+        updateChangeset({ review_requested: rr ? "yes" : void 0 });
+        tagSection.call(
+          rawTagEditor.tags(Object.assign({}, context.changeset.tags)).render
+        );
+      }
+    }
+    function getUploadBlockerMessage() {
+      var errors = context.validator().getIssuesBySeverity({ what: "edited", where: "all" }).error;
+      if (errors.length) {
+        return _t.append("commit.outstanding_errors_message", { count: errors.length });
+      } else {
+        var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
+        if (!hasChangesetComment) {
+          return _t.append("commit.comment_needed_message");
+        }
+      }
+      return null;
+    }
+    function changeTags(_2, changed, onInput) {
+      if (changed.hasOwnProperty("comment")) {
+        if (changed.comment === void 0) {
+          changed.comment = "";
+        }
+        if (!onInput) {
+          corePreferences("comment", changed.comment);
+          corePreferences("commentDate", Date.now());
+        }
+      }
+      if (changed.hasOwnProperty("source")) {
+        if (changed.source === void 0) {
+          corePreferences("source", null);
+        } else if (!onInput) {
+          corePreferences("source", changed.source);
+          corePreferences("commentDate", Date.now());
+        }
+      }
+      updateChangeset(changed, onInput);
+      if (_selection) {
+        _selection.call(render);
+      }
+    }
+    function findHashtags(tags, commentOnly) {
+      var detectedHashtags = commentHashtags();
+      if (detectedHashtags.length) {
+        corePreferences("hashtags", null);
+      }
+      if (!detectedHashtags.length || !commentOnly) {
+        detectedHashtags = detectedHashtags.concat(hashtagHashtags());
+      }
+      var allLowerCase = /* @__PURE__ */ new Set();
+      return detectedHashtags.filter(function(hashtag) {
+        var lowerCase = hashtag.toLowerCase();
+        if (!allLowerCase.has(lowerCase)) {
+          allLowerCase.add(lowerCase);
+          return true;
+        }
+        return false;
+      });
+      function commentHashtags() {
+        var matches = (tags.comment || "").replace(/http\S*/g, "").match(hashtagRegex);
+        return matches || [];
+      }
+      function hashtagHashtags() {
+        var matches = (tags.hashtags || "").split(/[,;\s]+/).map(function(s2) {
+          if (s2[0] !== "#") {
+            s2 = "#" + s2;
+          }
+          var matched = s2.match(hashtagRegex);
+          return matched && matched[0];
+        }).filter(Boolean);
+        return matches || [];
+      }
+    }
+    function isReviewRequested(tags) {
+      var rr = tags.review_requested;
+      if (rr === void 0) return false;
+      rr = rr.trim().toLowerCase();
+      return !(rr === "" || rr === "no");
+    }
+    function updateChangeset(changed, onInput) {
+      var tags = Object.assign({}, context.changeset.tags);
+      Object.keys(changed).forEach(function(k2) {
+        var v2 = changed[k2];
+        k2 = context.cleanTagKey(k2);
+        if (readOnlyTags.indexOf(k2) !== -1) return;
+        if (v2 === void 0) {
+          delete tags[k2];
+        } else if (onInput) {
+          tags[k2] = v2;
+        } else {
+          tags[k2] = context.cleanTagValue(v2);
+        }
+      });
+      if (!onInput) {
+        var commentOnly = changed.hasOwnProperty("comment") && changed.comment !== "";
+        var arr = findHashtags(tags, commentOnly);
+        if (arr.length) {
+          tags.hashtags = context.cleanTagValue(arr.join(";"));
+          corePreferences("hashtags", tags.hashtags);
+        } else {
+          delete tags.hashtags;
+          corePreferences("hashtags", null);
+        }
+      }
+      if (_userDetails2 && _userDetails2.changesets_count !== void 0) {
+        var changesetsCount = parseInt(_userDetails2.changesets_count, 10) + 1;
+        tags.changesets_count = String(changesetsCount);
+        if (changesetsCount <= 100) {
+          var s2;
+          s2 = corePreferences("walkthrough_completed");
+          if (s2) {
+            tags["ideditor:walkthrough_completed"] = s2;
+          }
+          s2 = corePreferences("walkthrough_progress");
+          if (s2) {
+            tags["ideditor:walkthrough_progress"] = s2;
+          }
+          s2 = corePreferences("walkthrough_started");
+          if (s2) {
+            tags["ideditor:walkthrough_started"] = s2;
+          }
+        }
+      } else {
+        delete tags.changesets_count;
+      }
+      if (!(0, import_fast_deep_equal10.default)(context.changeset.tags, tags)) {
+        context.changeset = context.changeset.update({ tags });
+      }
+    }
+    commit.reset = function() {
+      context.changeset = null;
+    };
+    return utilRebind(commit, dispatch14, "on");
+  }
+
+  // modules/modes/save.js
+  function modeSave(context) {
+    var mode = { id: "save" };
+    var keybinding = utilKeybinding("modeSave");
+    var commit = uiCommit(context).on("cancel", cancel);
+    var _conflictsUi;
+    var _location;
+    var _success;
+    var uploader = context.uploader().on("saveStarted.modeSave", function() {
+      keybindingOff();
+    }).on("willAttemptUpload.modeSave", prepareForSuccess).on("progressChanged.modeSave", showProgress).on("resultNoChanges.modeSave", function() {
+      cancel();
+    }).on("resultErrors.modeSave", showErrors).on("resultConflicts.modeSave", showConflicts).on("resultSuccess.modeSave", showSuccess);
+    function cancel() {
+      context.enter(modeBrowse(context));
+    }
+    function showProgress(num, total) {
+      var modal = context.container().select(".loading-modal .modal-section");
+      var progress = modal.selectAll(".progress").data([0]);
+      progress.enter().append("div").attr("class", "progress").merge(progress).text(_t("save.conflict_progress", { num, total }));
+    }
+    function showConflicts(changeset, conflicts, origChanges) {
+      var selection2 = context.container().select(".sidebar").append("div").attr("class", "sidebar-component");
+      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
+      _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on("cancel", function() {
+        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
+        selection2.remove();
+        keybindingOn();
+        uploader.cancelConflictResolution();
+      }).on("save", function() {
+        context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
+        selection2.remove();
+        uploader.processResolvedConflicts(changeset);
+      });
+      selection2.call(_conflictsUi);
+    }
+    function showErrors(errors) {
+      keybindingOn();
+      var selection2 = uiConfirm(context.container());
+      selection2.select(".modal-section.header").append("h3").text(_t("save.error"));
+      addErrors(selection2, errors);
+      selection2.okButton();
+    }
+    function addErrors(selection2, data) {
+      var message = selection2.select(".modal-section.message-text");
+      var items = message.selectAll(".error-container").data(data);
+      var enter = items.enter().append("div").attr("class", "error-container");
+      enter.append("a").attr("class", "error-description").attr("href", "#").classed("hide-toggle", true).text(function(d2) {
+        return d2.msg || _t("save.unknown_error_details");
+      }).on("click", function(d3_event) {
+        d3_event.preventDefault();
+        var error = select_default2(this);
+        var detail = select_default2(this.nextElementSibling);
+        var exp2 = error.classed("expanded");
+        detail.style("display", exp2 ? "none" : "block");
+        error.classed("expanded", !exp2);
+      });
+      var details = enter.append("div").attr("class", "error-detail-container").style("display", "none");
+      details.append("ul").attr("class", "error-detail-list").selectAll("li").data(function(d2) {
+        return d2.details || [];
+      }).enter().append("li").attr("class", "error-detail-item").text(function(d2) {
+        return d2;
+      });
+      items.exit().remove();
+    }
+    function showSuccess(changeset) {
+      commit.reset();
+      var ui = _success.changeset(changeset).location(_location).on("cancel", function() {
+        context.ui().sidebar.hide();
+      });
+      context.enter(modeBrowse(context).sidebar(ui));
+    }
+    function keybindingOn() {
+      select_default2(document).call(keybinding.on("\u238B", cancel, true));
+    }
+    function keybindingOff() {
+      select_default2(document).call(keybinding.unbind);
+    }
+    function prepareForSuccess() {
+      _success = uiSuccess(context);
+      _location = null;
+      if (!services.geocoder) return;
+      services.geocoder.reverse(context.map().center(), function(err, result) {
+        if (err || !result || !result.address) return;
+        var addr = result.address;
+        var place = addr && (addr.town || addr.city || addr.county) || "";
+        var region = addr && (addr.state || addr.country) || "";
+        var separator = place && region ? _t("success.thank_you_where.separator") : "";
+        _location = _t(
+          "success.thank_you_where.format",
+          { place, separator, region }
+        );
+      });
+    }
+    mode.selectedIDs = function() {
+      return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
+    };
+    mode.enter = function() {
+      context.ui().sidebar.expand();
+      function done() {
+        context.ui().sidebar.show(commit);
+      }
+      keybindingOn();
+      context.container().selectAll(".main-content").classed("active", false).classed("inactive", true);
+      var osm = context.connection();
+      if (!osm) {
+        cancel();
+        return;
+      }
+      if (osm.authenticated()) {
+        done();
+      } else {
+        osm.authenticate(function(err) {
+          if (err) {
+            cancel();
+          } else {
+            done();
+          }
+        });
+      }
+    };
+    mode.exit = function() {
+      keybindingOff();
+      context.container().selectAll(".main-content").classed("active", true).classed("inactive", false);
+      context.ui().sidebar.hide();
+    };
+    return mode;
+  }
+
+  // modules/modes/select_error.js
+  function modeSelectError(context, selectedErrorID, selectedErrorService) {
+    var mode = {
+      id: "select-error",
+      button: "browse"
+    };
+    var keybinding = utilKeybinding("select-error");
+    var errorService = services[selectedErrorService];
+    var errorEditor;
+    switch (selectedErrorService) {
+      case "keepRight":
+        errorEditor = uiKeepRightEditor(context).on("change", function() {
+          context.map().pan([0, 0]);
+          var error = checkSelectedID();
+          if (!error) return;
+          context.ui().sidebar.show(errorEditor.error(error));
+        });
+        break;
+      case "osmose":
+        errorEditor = uiOsmoseEditor(context).on("change", function() {
+          context.map().pan([0, 0]);
+          var error = checkSelectedID();
+          if (!error) return;
+          context.ui().sidebar.show(errorEditor.error(error));
+        });
+        break;
+    }
+    var behaviors = [
+      behaviorBreathe(context),
+      behaviorHover(context),
+      behaviorSelect(context),
+      behaviorLasso(context),
+      modeDragNode(context).behavior,
+      modeDragNote(context).behavior
+    ];
+    function checkSelectedID() {
+      if (!errorService) return;
+      var error = errorService.getError(selectedErrorID);
+      if (!error) {
+        context.enter(modeBrowse(context));
+      }
+      return error;
+    }
+    mode.zoomToSelected = function() {
+      if (!errorService) return;
+      var error = errorService.getError(selectedErrorID);
+      if (error) {
+        context.map().centerZoomEase(error.loc, 20);
+      }
+    };
+    mode.enter = function() {
+      var error = checkSelectedID();
+      if (!error) return;
+      behaviors.forEach(context.install);
+      keybinding.on(_t("inspector.zoom_to.key"), mode.zoomToSelected).on("\u238B", esc, true);
+      select_default2(document).call(keybinding);
+      selectError();
+      var sidebar = context.ui().sidebar;
+      sidebar.show(errorEditor.error(error));
+      context.map().on("drawn.select-error", selectError);
+      function selectError(d3_event, drawn) {
+        if (!checkSelectedID()) return;
+        var selection2 = context.surface().selectAll(".itemId-" + selectedErrorID + "." + selectedErrorService);
+        if (selection2.empty()) {
+          var source = d3_event && d3_event.type === "zoom" && d3_event.sourceEvent;
+          if (drawn && source && (source.type === "pointermove" || source.type === "mousemove" || source.type === "touchmove")) {
+            context.enter(modeBrowse(context));
+          }
+        } else {
+          selection2.classed("selected", true);
+          context.selectedErrorID(selectedErrorID);
+        }
+      }
+      function esc() {
+        if (context.container().select(".combobox").size()) return;
+        context.enter(modeBrowse(context));
+      }
+    };
+    mode.exit = function() {
+      behaviors.forEach(context.uninstall);
+      select_default2(document).call(keybinding.unbind);
+      context.surface().selectAll(".qaItem.selected").classed("selected hover", false);
+      context.map().on("drawn.select-error", null);
+      context.ui().sidebar.hide();
+      context.selectedErrorID(null);
+      context.features().forceVisible([]);
+    };
+    return mode;
+  }
+
+  // modules/core/context.js
+  function coreContext() {
+    const dispatch14 = dispatch_default("enter", "exit", "change");
+    let context = utilRebind({}, dispatch14, "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;
+        }
+      };
+    }
+    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));
+        }
+      });
+      _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));
+        }
+      });
+      _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.loadNote = (entityID, callback) => {
+      if (_connection) {
+        const cid = _connection.getConnectionId();
+        _connection.loadEntityNote(entityID, afterLoad(cid, callback));
+      }
+    };
+    context.zoomToEntity = (entityID, zoomTo) => {
+      context.zoomToEntities([entityID], zoomTo);
+    };
+    context.zoomToEntities = (entityIDs, zoomTo) => {
+      let loadedEntities = [];
+      const throttledZoomTo = throttle_default(() => _map.zoomTo(loadedEntities), 500);
+      entityIDs.forEach((entityID) => context.loadEntity(entityID, (err, result) => {
+        if (err) return;
+        const entity = result.data.find((e3) => e3.id === entityID);
+        if (!entity) return;
+        loadedEntities.push(entity);
+        if (zoomTo !== false) {
+          throttledZoomTo();
+        }
+      }));
+      _map.on("drawn.zoomToEntity", () => {
+        if (!entityIDs.every((entityID) => context.hasEntity(entityID))) return;
+        _map.on("drawn.zoomToEntity", null);
+        context.on("enter.zoomToEntity", null);
+        context.enter(modeSelect(context, entityIDs));
+      });
+      context.on("enter.zoomToEntity", () => {
+        if (_mode.id !== "browse") {
+          _map.on("drawn.zoomToEntity", null);
+          context.on("enter.zoomToEntity", null);
+        }
+      });
+    };
+    context.zoomToNote = (noteId, zoomTo) => {
+      context.loadNote(noteId, (err, result) => {
+        if (err) return;
+        const entity = result.data.find((e3) => e3.id === noteId);
+        if (entity) {
+          const note = services.osm.getNote(noteId);
+          if (zoomTo !== false) {
+            context.map().centerZoom(note.loc, 15);
+          }
+          const noteLayer = context.layers().layer("notes");
+          noteLayer.enabled(true);
+          context.enter(modeSelectNote(context, noteId));
+        }
+      });
+    };
+    let _minEditableZoom = 16;
+    context.minEditableZoom = function(val) {
+      if (!arguments.length) return _minEditableZoom;
+      _minEditableZoom = val;
+      if (_connection) {
+        _connection.tileZoom(val);
+      }
+      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;
+      };
+    }
+    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();
+        dispatch14.call("exit", this, _mode);
+      }
+      _mode = newMode;
+      _mode.enter();
+      dispatch14.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;
+      dispatch14.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;
     };
-    let _apiConnections;
-    context.apiConnections = function(val) {
-      if (!arguments.length)
-        return _apiConnections;
-      _apiConnections = val;
+    context.containerNode = function(val) {
+      if (!arguments.length) return context.container().node();
+      context.container(select_default2(val));
       return context;
     };
-    context.locale = function(locale2) {
-      if (!arguments.length)
-        return _mainLocalizer.localeCode();
-      _mainLocalizer.preferredLocaleCodes(locale2);
+    let _embed;
+    context.embed = function(val) {
+      if (!arguments.length) return _embed;
+      _embed = val;
       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();
-            }
+    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/".concat(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);
+      }
+      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();
           }
-          if (typeof callback === "function") {
-            callback(err);
+        });
+        _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();
+          });
+        }
+      }
+    };
+    return context;
+  }
+
+  // modules/services/nominatim.js
+  var apibase = nominatimApiUrl;
+  var _inflight = {};
+  var _nominatimCache;
+  var nominatim_default = {
+    init: function() {
+      _inflight = {};
+      _nominatimCache = new RBush();
+    },
+    reset: function() {
+      Object.values(_inflight).forEach(function(controller) {
+        controller.abort();
+      });
+      _inflight = {};
+      _nominatimCache = new RBush();
+    },
+    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);
+        }
+      });
+    },
+    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) {
+      const params = {
+        q: val,
+        limit: 10,
+        format: "json"
+      };
+      var url = apibase + "search?" + 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);
+        }
+        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_polygon4 = __toESM(require_which_polygon(), 1);
+
+  // node_modules/name-suggestion-index/lib/simplify.js
+  var import_diacritics3 = __toESM(require_diacritics(), 1);
+  function simplify2(str) {
+    if (typeof str !== "string") return "";
+    return import_diacritics3.default.remove(
+      str.replace(/&/g, "and").replace(/İ/ig, "i").replace(/[\s\-=_!"#%'*{},.\/:;?\(\)\[\]@\\$\^*+<>«»~`’\u00a1\u00a7\u00b6\u00b7\u00bf\u037e\u0387\u055a-\u055f\u0589\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0af0\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f14\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1360-\u1368\u166d\u166e\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u1805\u1807-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cc0-\u1cc7\u1cd3\u2000-\u206f\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e7f\u3001-\u3003\u303d\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uaaf0\uaaf1\uabeb\ufe10-\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49-\ufe4c\ufe50-\ufe52\ufe54-\ufe57\ufe5f-\ufe61\ufe68\ufe6a\ufe6b\ufeff\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, "").toLowerCase()
+    );
+  }
+
+  // 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+)$"
+        }
+      },
+      flags: {
+        emoji: "\u{1F6A9}",
+        mainTag: "flag:wikidata",
+        nameTags: {
+          primary: "^(flag:name|flag:name:\\w+)$",
+          alternate: "^(country|country:\\w+|flag|flag:\\w+|subject|subject:\\w+)$"
+        }
+      },
+      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+)$"
+        }
+      },
+      transit: {
+        emoji: "\u{1F687}",
+        mainTag: "network:wikidata",
+        sourceTags: ["network"],
+        nameTags: {
+          primary: "^network$",
+          alternate: "^(operator|operator:\\w+|network:\\w+|\\w+_name|\\w+_name:\\w+)$"
+        }
+      }
+    }
+  };
+
+  // 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((s2) => this.genericWords.set(s2, new RegExp(s2, "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;
+      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 t2 = parts[0];
+        const k2 = parts[1];
+        const v2 = parts[2];
+        const thiskv = "".concat(k2, "/").concat(v2);
+        const tree = trees[t2];
+        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((s2) => branch.excludeGeneric.set(s2, new RegExp(s2, "i")));
+        (exclude.named || []).forEach((s2) => branch.excludeNamed.set(s2, new RegExp(s2, "i")));
+        const excludeRegexes = [...branch.excludeGeneric.values(), ...branch.excludeNamed.values()];
+        let items = category.items;
+        if (!Array.isArray(items) || !items.length) return;
+        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(t2, k2, v2);
+        const genericKV = /* @__PURE__ */ new Set(["".concat(k2, "/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("".concat(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;
           }
-          return;
-        } else if (_connection && _connection.getConnectionId() !== cid) {
-          if (typeof callback === "function") {
-            callback({ message: "Connection Switched", status: -1 });
+          let kvTags = ["".concat(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", t2, kv, simplify2(osmvalue), item.id));
+            } else if (alternateName.test(osmkey)) {
+              kvTags.forEach((kv) => insertName("alternate", t2, 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", t2, kv, nsimple, item.id);
+                keepMatchNames.add(matchName);
+              }
+            });
+          });
+          if (keepMatchNames.size) {
+            item.matchNames = Array.from(keepMatchNames);
+          } else {
+            delete item.matchNames;
           }
+        });
+      });
+      function insertName(which, t2, kv, nsimple, itemID) {
+        if (!nsimple) {
+          that.warnings.push("Warning: skipping empty ".concat(which, " name for item ").concat(t2, "/").concat(kv, ": ").concat(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 = "".concat(kv, "/").concat(nsimple);
+          const existing = seenTree.get(kvnsimple);
+          if (existing && existing !== t2) {
+            const items = Array.from(leaf);
+            that.warnings.push('Duplicate cache key "'.concat(kvnsimple, '" in trees "').concat(t2, '" and "').concat(existing, '", check items: ').concat(items));
+            return;
           }
+          seenTree.set(kvnsimple, t2);
         }
-      });
-      _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(t2, k2, v2) {
+        return t2 === "flags" || t2 === "transit" || k2 === "landuse" || v2 === "atm" || v2 === "bicycle_parking" || v2 === "car_sharing" || v2 === "caravan_site" || v2 === "charging_station" || v2 === "dog_park" || v2 === "parking" || v2 === "phone" || v2 === "playground" || v2 === "post_box" || v2 === "public_bookcase" || v2 === "recycling" || v2 === "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())
-        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();
+    //
+    // `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;
+      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: ".concat(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 ".concat(resolved.id, " for ").concat(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(k2, v2, n3, 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(n3);
+      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 = "".concat(k2, "/").concat(v2);
+        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 i3 = 0; i3 < matchGroup.length; i3++) {
+            const otherkv = matchGroup[i3];
+            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(n3));
+          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(n3));
+          if (regex) {
+            results.push({ match: "excludeNamed", pattern: String(regex), kv });
+            return;
+          }
+          regex = [...branch.excludeGeneric.values()].find((regex2) => regex2.test(n3));
+          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 = {
@@ -69700,21 +75791,21 @@ ${content}</tr>
   var notBranches = /(coop|express|wireless|factory|outlet)/i;
   function setNsiSources() {
     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 v2 = (0, import_vparse2.default)(nsiVersion);
+    const vMinor = "".concat(v2.major, ".").concat(v2.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) {
-      if (!fileMap[k])
-        fileMap[k] = sources[k];
+    for (const k2 in sources) {
+      if (!fileMap[k2]) fileMap[k2] = sources[k2];
     }
   }
   function loadNsiPresets() {
@@ -69723,6 +75814,17 @@ ${content}</tr>
       _mainFileFetcher.get("nsi_features")
     ]).then((vals) => {
       Object.values(vals[0].presets).forEach((preset) => preset.suggestion = true);
+      Object.values(vals[0].presets).forEach((preset) => {
+        if (preset.tags["brand:wikidata"]) {
+          preset.removeTags = { "brand:wikipedia": "*", ...preset.removeTags || preset.addTags || preset.tags };
+        }
+        if (preset.tags["operator:wikidata"]) {
+          preset.removeTags = { "operator:wikipedia": "*", ...preset.removeTags || preset.addTags || preset.tags };
+        }
+        if (preset.tags["network:wikidata"]) {
+          preset.removeTags = { "network:wikipedia": "*", ...preset.removeTags || preset.addTags || preset.tags };
+        }
+      });
       _mainPresetIndex.merge({
         presets: vals[0].presets,
         featureCollection: vals[1]
@@ -69738,29 +75840,61 @@ ${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);
-        const t = parts[0];
-        const k = parts[1];
-        const v = parts[2];
-        let vmap = _nsi.kvt.get(k);
+        const t2 = parts[0];
+        const k2 = parts[1];
+        const v2 = parts[2];
+        let vmap = _nsi.kvt.get(k2);
         if (!vmap) {
           vmap = /* @__PURE__ */ new Map();
-          _nsi.kvt.set(k, vmap);
+          _nsi.kvt.set(k2, vmap);
         }
-        vmap.set(v, t);
-        const tree = _nsi.trees[t];
+        vmap.set(v2, t2);
+        const tree = _nsi.trees[t2];
         const mainTag = tree.mainTag;
         const items = category.items || [];
         items.forEach((item) => {
@@ -69769,10 +75903,8 @@ ${content}</tr>
           _nsi.ids.set(item.id, item);
           const wd = item.tags[mainTag];
           const wp = item.tags[mainTag.replace("wikidata", "wikipedia")];
-          if (wd)
-            _nsi.qids.set(wd, wd);
-          if (wp && wd)
-            _nsi.qids.set(wp, wd);
+          if (wd) _nsi.qids.set(wd, wd);
+          if (wp && wd) _nsi.qids.set(wp, wd);
         });
       });
     });
@@ -69782,17 +75914,14 @@ ${content}</tr>
     let alternate = /* @__PURE__ */ new Set();
     Object.keys(tags).forEach((osmkey) => {
       const osmvalue = tags[osmkey];
-      if (!osmvalue)
-        return;
-      if (osmkey === "route_master")
-        osmkey = "route";
+      if (!osmvalue) return;
+      if (osmkey === "route_master") osmkey = "route";
       const vmap = _nsi.kvt.get(osmkey);
-      if (!vmap)
-        return;
+      if (!vmap) return;
       if (vmap.get(osmvalue)) {
-        primary.add(`${osmkey}/${osmvalue}`);
+        primary.add("".concat(osmkey, "/").concat(osmvalue));
       } else if (osmvalue === "yes") {
-        alternate.add(`${osmkey}/${osmvalue}`);
+        alternate.add("".concat(osmkey, "/").concat(osmvalue));
       }
     });
     const preset = _mainPresetIndex.matchTags(tags, "area");
@@ -69803,25 +75932,21 @@ ${content}</tr>
   }
   function identifyTree(tags) {
     let unknown;
-    let t;
+    let t2;
     Object.keys(tags).forEach((osmkey) => {
-      if (t)
-        return;
+      if (t2) return;
       const osmvalue = tags[osmkey];
-      if (!osmvalue)
-        return;
-      if (osmkey === "route_master")
-        osmkey = "route";
+      if (!osmvalue) return;
+      if (osmkey === "route_master") osmkey = "route";
       const vmap = _nsi.kvt.get(osmkey);
-      if (!vmap)
-        return;
+      if (!vmap) return;
       if (osmvalue === "yes") {
         unknown = "unknown";
       } else {
-        t = vmap.get(osmvalue);
+        t2 = vmap.get(osmvalue);
       }
     });
-    return t || unknown || null;
+    return t2 || unknown || null;
   }
   function gatherNames(tags) {
     const empty2 = { primary: /* @__PURE__ */ new Set(), alternate: /* @__PURE__ */ new Set() };
@@ -69830,26 +75955,26 @@ ${content}</tr>
     let foundSemi = false;
     let testNameFragments = false;
     let patterns2;
-    let t = identifyTree(tags);
-    if (!t)
-      return empty2;
-    if (t === "transit") {
+    let t2 = identifyTree(tags);
+    if (!t2) return empty2;
+    if (t2 === "transit") {
       patterns2 = {
         primary: /^network$/i,
         alternate: /^(operator|operator:\w+|network:\w+|\w+_name|\w+_name:\w+)$/i
       };
-    } else if (t === "flags") {
+    } else if (t2 === "flags") {
       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") {
+    } else if (t2 === "brands") {
       testNameFragments = true;
       patterns2 = {
         primary: /^(name|name:\w+)$/i,
         alternate: /^(brand|brand:\w+|operator|operator:\w+|\w+_name|\w+_name:\w+)/i
       };
-    } else if (t === "operators") {
+    } else if (t2 === "operators") {
       testNameFragments = true;
       patterns2 = {
         primary: /^(name|name:\w+|operator|operator:\w+)$/i,
@@ -69871,8 +75996,7 @@ ${content}</tr>
     }
     Object.keys(tags).forEach((osmkey) => {
       const osmvalue = tags[osmkey];
-      if (!osmvalue)
-        return;
+      if (!osmvalue) return;
       if (isNamelike(osmkey, "primary")) {
         if (/;/.test(osmvalue)) {
           foundSemi = true;
@@ -69902,22 +76026,21 @@ ${content}</tr>
       return { primary, alternate };
     }
     function isNamelike(osmkey, which) {
-      if (osmkey === "old_name")
-        return false;
+      if (osmkey === "old_name") return false;
       return patterns2[which].test(osmkey) && !notNames.test(osmkey);
     }
   }
   function gatherTuples(tryKVs, tryNames) {
     let tuples = [];
     ["primary", "alternate"].forEach((whichName) => {
-      const arr = Array.from(tryNames[whichName]).sort((a, b) => b.length - a.length);
-      arr.forEach((n2) => {
+      const arr = Array.from(tryNames[whichName]).sort((a2, b2) => b2.length - a2.length);
+      arr.forEach((n3) => {
         ["primary", "alternate"].forEach((whichKV) => {
           tryKVs[whichKV].forEach((kv) => {
             const parts = kv.split("/", 2);
-            const k = parts[0];
-            const v = parts[1];
-            tuples.push({ k, v, n: n2 });
+            const k2 = parts[0];
+            const v2 = parts[1];
+            tuples.push({ k: k2, v: v2, n: n3 });
           });
         });
       });
@@ -69943,7 +76066,7 @@ ${content}</tr>
         }
         if (replace && replace.wikipedia !== void 0) {
           changed = true;
-          const wpkey = `${prefix}wikipedia`;
+          const wpkey = "".concat(prefix, "wikipedia");
           if (replace.wikipedia) {
             newTags[wpkey] = replace.wikipedia;
           } else {
@@ -69959,69 +76082,58 @@ ${content}</tr>
     }
     const tryNames = gatherNames(tags);
     const foundQID = _nsi.qids.get(tags.wikidata) || _nsi.qids.get(tags.wikipedia);
-    if (foundQID)
-      tryNames.primary.add(foundQID);
+    if (foundQID) tryNames.primary.add(foundQID);
     if (!tryNames.primary.size && !tryNames.alternate.size) {
       return changed ? { newTags, matched: null } : null;
     }
     const tuples = gatherTuples(tryKVs, tryNames);
-    let foundPrimary = false;
-    let bestItem;
-    for (let i2 = 0; i2 < tuples.length && !foundPrimary; i2++) {
-      const tuple = tuples[i2];
+    for (let i3 = 0; i3 < tuples.length; i3++) {
+      const tuple = tuples[i3];
       const hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n, loc);
-      if (!hits || !hits.length)
-        continue;
-      if (hits[0].match !== "primary" && hits[0].match !== "alternate")
-        break;
+      if (!hits || !hits.length) continue;
+      if (hits[0].match !== "primary" && hits[0].match !== "alternate") break;
+      let itemID, item;
       for (let j2 = 0; j2 < hits.length; j2++) {
         const hit = hits[j2];
-        const isPrimary = hits[j2].match === "primary";
-        const itemID = hit.itemID;
-        if (_nsi.dissolved[itemID])
-          continue;
-        const item = _nsi.ids.get(itemID);
-        if (!item)
-          continue;
+        itemID = hit.itemID;
+        if (_nsi.dissolved[itemID]) continue;
+        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) {
+        const notQID = newTags["not:".concat(mainTag)];
+        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];
-      const v = parts[2];
+      const k2 = parts[1];
+      const v2 = parts[2];
       const category = _nsi.data[tkv];
       const properties = category.properties || {};
       let preserveTags = item.preserveTags || properties.preserveTags || [];
       ["building", "emergency", "internet_access", "takeaway"].forEach((osmkey) => {
-        if (k !== osmkey)
-          preserveTags.push(`^${osmkey}$`);
+        if (k2 !== osmkey) preserveTags.push("^".concat(osmkey, "$"));
       });
-      const regexes = preserveTags.map((s) => new RegExp(s, "i"));
+      const regexes = preserveTags.map((s2) => new RegExp(s2, "i"));
       let keepTags = {};
       Object.keys(newTags).forEach((osmkey) => {
         if (regexes.some((regex) => regex.test(osmkey))) {
           keepTags[osmkey] = newTags[osmkey];
         }
       });
-      _nsi.kvt.forEach((vmap, k2) => {
-        if (newTags[k2] === "yes")
-          delete newTags[k2];
+      _nsi.kvt.forEach((vmap, k3) => {
+        if (newTags[k3] === "yes") delete newTags[k3];
       });
       if (foundQID) {
         delete newTags.wikipedia;
@@ -70043,15 +76155,14 @@ ${content}</tr>
           for (let split = nameParts.length; split > 0; split--) {
             const name = nameParts.slice(0, split).join(" ");
             const branch = nameParts.slice(split).join(" ");
-            const nameHits = _nsi.matcher.match(k, v, name, loc);
-            if (!nameHits || !nameHits.length)
-              continue;
+            const nameHits = _nsi.matcher.match(k2, v2, name, loc);
+            if (!nameHits || !nameHits.length) continue;
             if (nameHits.some((hit) => hit.itemID === itemID)) {
               if (branch) {
                 if (notBranches.test(branch)) {
                   newTags.name = origName;
                 } else {
-                  const branchHits = _nsi.matcher.match(k, v, branch, loc);
+                  const branchHits = _nsi.matcher.match(k2, v2, branch, loc);
                   if (branchHits && branchHits.length) {
                     if (branchHits[0].match === "primary" || branchHits[0].match === "alternate") {
                       return null;
@@ -70071,79 +76182,104 @@ ${content}</tr>
     return changed ? { newTags, matched: null } : null;
   }
   function _isGenericName(tags) {
-    const n2 = tags.name;
-    if (!n2)
-      return false;
-    const tryNames = { primary: /* @__PURE__ */ new Set([n2]), alternate: /* @__PURE__ */ new Set() };
+    const n3 = tags.name;
+    if (!n3) return false;
+    const tryNames = { primary: /* @__PURE__ */ new Set([n3]), alternate: /* @__PURE__ */ new Set() };
     const tryKVs = gatherKVs(tags);
-    if (!tryKVs.primary.size && !tryKVs.alternate.size)
-      return false;
+    if (!tryKVs.primary.size && !tryKVs.alternate.size) return false;
     const tuples = gatherTuples(tryKVs, tryNames);
-    for (let i2 = 0; i2 < tuples.length; i2++) {
-      const tuple = tuples[i2];
+    for (let i3 = 0; i3 < tuples.length; i3++) {
+      const tuple = tuples[i3];
       const hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n);
-      if (hits && hits.length && hits[0].match === "excludeGeneric")
-        return true;
+      if (hits && hits.length && hits[0].match === "excludeGeneric") return true;
     }
     return false;
   }
   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
   };
 
   // modules/services/kartaview.js
-  var import_rbush8 = __toESM(require_rbush_min());
   var apibase2 = "https://kartaview.org";
   var maxResults = 1e3;
   var tileZoom = 14;
-  var tiler4 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
+  var tiler3 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
   var dispatch6 = dispatch_default("loadedImages");
-  var imgZoom = zoom_default2().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
+  var imgZoom2 = zoom_default2().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
   var _oscCache;
   var _oscSelectedImage;
   var _loadViewerPromise2;
-  function abortRequest4(controller) {
+  function abortRequest3(controller) {
     controller.abort();
   }
-  function maxPageAtZoom(z) {
-    if (z < 15)
-      return 2;
-    if (z === 15)
-      return 5;
-    if (z === 16)
-      return 10;
-    if (z === 17)
-      return 20;
-    if (z === 18)
-      return 40;
-    if (z > 18)
-      return 80;
+  function maxPageAtZoom(z2) {
+    if (z2 < 15) return 2;
+    if (z2 === 15) return 5;
+    if (z2 === 16) return 10;
+    if (z2 === 17) return 20;
+    if (z2 === 18) return 40;
+    if (z2 > 18) return 80;
   }
   function loadTiles2(which, url, projection2) {
     var currZoom = Math.floor(geoScaleToZoom(projection2.scale()));
-    var tiles = tiler4.getTiles(projection2);
+    var tiles = tiler3.getTiles(projection2);
     var cache = _oscCache[which];
-    Object.keys(cache.inflight).forEach(function(k) {
+    Object.keys(cache.inflight).forEach(function(k2) {
       var wanted = tiles.find(function(tile) {
-        return k.indexOf(tile.id + ",") === 0;
+        return k2.indexOf(tile.id + ",") === 0;
       });
       if (!wanted) {
-        abortRequest4(cache.inflight[k]);
-        delete cache.inflight[k];
+        abortRequest3(cache.inflight[k2]);
+        delete cache.inflight[k2];
       }
     });
     tiles.forEach(function(tile) {
@@ -70152,20 +76288,19 @@ ${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;
+    if (nextPage > maxPages) return;
     var id2 = tile.id + "," + String(nextPage);
-    if (cache.loaded[id2] || cache.inflight[id2])
-      return;
+    if (cache.loaded[id2] || cache.inflight[id2]) return;
     var controller = new AbortController();
     cache.inflight[id2] = controller;
     var options2 = {
@@ -70180,11 +76315,11 @@ ${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;
+        var d2;
         if (which === "images") {
-          d = {
+          d2 = {
             loc,
             key: item.id,
             ca: +item.heading,
@@ -70194,23 +76329,23 @@ ${content}</tr>
             sequence_id: item.sequence_id,
             sequence_index: +item.sequence_index
           };
-          var seq = _oscCache.sequences[d.sequence_id];
+          var seq = _oscCache.sequences[d2.sequence_id];
           if (!seq) {
             seq = { rotation: 0, images: [] };
-            _oscCache.sequences[d.sequence_id] = seq;
+            _oscCache.sequences[d2.sequence_id] = seq;
           }
-          seq.images[d.sequence_index] = d;
-          _oscCache.images.forImageKey[d.key] = d;
+          seq.images[d2.sequence_index] = d2;
+          _oscCache.images.forImageKey[d2.key] = d2;
         }
         return {
           minX: loc[0],
           minY: loc[1],
           maxX: loc[0],
           maxY: loc[1],
-          data: d
+          data: d2
         };
       });
-      cache.rtree.load(features2);
+      cache.rtree.load(features);
       if (data.currentPageItems.length === maxResults) {
         cache.nextPage[tile.id] = nextPage + 1;
         loadNextTilePage(which, currZoom, url, tile);
@@ -70226,9 +76361,9 @@ ${content}</tr>
     });
   }
   function partitionViewport2(projection2) {
-    var z = geoScaleToZoom(projection2.scale());
-    var z2 = Math.ceil(z * 2) / 2 + 2.5;
-    var tiler8 = utilTiler().zoomExtent([z2, z2]);
+    var z2 = geoScaleToZoom(projection2.scale());
+    var z22 = Math.ceil(z2 * 2) / 2 + 2.5;
+    var tiler8 = utilTiler().zoomExtent([z22, z22]);
     return tiler8.getTiles(projection2).map(function(tile) {
       return tile.extent;
     });
@@ -70236,8 +76371,8 @@ ${content}</tr>
   function searchLimited2(limit, projection2, rtree) {
     limit = limit || 5;
     return partitionViewport2(projection2).reduce(function(result, extent) {
-      var found = rtree.search(extent.bbox()).slice(0, limit).map(function(d) {
-        return d.data;
+      var found = rtree.search(extent.bbox()).slice(0, limit).map(function(d2) {
+        return d2.data;
       });
       return found.length ? result.concat(found) : result;
     }, []);
@@ -70251,10 +76386,10 @@ ${content}</tr>
     },
     reset: function() {
       if (_oscCache) {
-        Object.values(_oscCache.images.inflight).forEach(abortRequest4);
+        Object.values(_oscCache.images.inflight).forEach(abortRequest3);
       }
       _oscCache = {
-        images: { inflight: {}, loaded: {}, nextPage: {}, rtree: new import_rbush8.default(), forImageKey: {} },
+        images: { inflight: {}, loaded: {}, nextPage: {}, rtree: new RBush(), forImageKey: {} },
         sequences: {}
       };
       _oscSelectedImage = null;
@@ -70267,10 +76402,10 @@ ${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) {
-        sequenceKeys[d.data.sequence_id] = true;
+      _oscCache.images.rtree.search(bbox2).forEach(function(d2) {
+        sequenceKeys[d2.data.sequence_id] = true;
       });
       var lineStrings = [];
       Object.keys(sequenceKeys).forEach(function(sequenceKey) {
@@ -70279,8 +76414,8 @@ ${content}</tr>
         if (images) {
           lineStrings.push({
             type: "LineString",
-            coordinates: images.map(function(d) {
-              return d.loc;
+            coordinates: images.map(function(d2) {
+              return d2.loc;
             }).filter(Boolean),
             properties: {
               captured_at: images[0] ? images[0].captured_at : null,
@@ -70300,11 +76435,10 @@ ${content}</tr>
       loadTiles2("images", url, projection2);
     },
     ensureViewerLoaded: function(context) {
-      if (_loadViewerPromise2)
-        return _loadViewerPromise2;
+      if (_loadViewerPromise2) return _loadViewerPromise2;
       var wrap2 = context.container().select(".photoviewer").selectAll(".kartaview-wrapper").data([0]);
       var that = this;
-      var wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper kartaview-wrapper").classed("hide", true).call(imgZoom.on("zoom", zoomPan)).on("dblclick.zoom", null);
+      var wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper kartaview-wrapper").classed("hide", true).call(imgZoom2.on("zoom", zoomPan2)).on("dblclick.zoom", null);
       wrapEnter.append("div").attr("class", "photo-attribution fillD");
       var controlsEnter = wrapEnter.append("div").attr("class", "photo-controls-wrap").append("div").attr("class", "photo-controls");
       controlsEnter.append("button").on("click.back", step(-1)).text("\u25C4");
@@ -70313,44 +76447,37 @@ ${content}</tr>
       controlsEnter.append("button").on("click.forward", step(1)).text("\u25BA");
       wrapEnter.append("div").attr("class", "kartaview-image-wrap");
       context.ui().photoviewer.on("resize.kartaview", function(dimensions) {
-        imgZoom = zoom_default2().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on("zoom", zoomPan);
+        imgZoom2.extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]);
       });
-      function zoomPan(d3_event) {
-        var t = d3_event.transform;
-        context.container().select(".photoviewer .kartaview-image-wrap").call(utilSetTransform, t.x, t.y, t.k);
+      function zoomPan2(d3_event) {
+        var t2 = d3_event.transform;
+        context.container().select(".photoviewer .kartaview-image-wrap").call(utilSetTransform, t2.x, t2.y, t2.k);
       }
       function rotate(deg) {
         return function() {
-          if (!_oscSelectedImage)
-            return;
+          if (!_oscSelectedImage) return;
           var sequenceKey = _oscSelectedImage.sequence_id;
           var sequence = _oscCache.sequences[sequenceKey];
-          if (!sequence)
-            return;
-          var r = sequence.rotation || 0;
-          r += deg;
-          if (r > 180)
-            r -= 360;
-          if (r < -180)
-            r += 360;
-          sequence.rotation = r;
+          if (!sequence) return;
+          var r2 = sequence.rotation || 0;
+          r2 += deg;
+          if (r2 > 180) r2 -= 360;
+          if (r2 < -180) r2 += 360;
+          sequence.rotation = r2;
           var wrap3 = context.container().select(".photoviewer .kartaview-wrapper");
-          wrap3.transition().duration(100).call(imgZoom.transform, identity2);
-          wrap3.selectAll(".kartaview-image").transition().duration(100).style("transform", "rotate(" + r + "deg)");
+          wrap3.transition().duration(100).call(imgZoom2.transform, identity2);
+          wrap3.selectAll(".kartaview-image").transition().duration(100).style("transform", "rotate(" + r2 + "deg)");
         };
       }
       function step(stepBy) {
         return function() {
-          if (!_oscSelectedImage)
-            return;
+          if (!_oscSelectedImage) return;
           var sequenceKey = _oscSelectedImage.sequence_id;
           var sequence = _oscCache.sequences[sequenceKey];
-          if (!sequence)
-            return;
+          if (!sequence) return;
           var nextIndex = _oscSelectedImage.sequence_index + stepBy;
           var nextImage = sequence.images[nextIndex];
-          if (!nextImage)
-            return;
+          if (!nextImage) return;
           context.map().centerEase(nextImage.loc);
           that.selectImage(context, nextImage.key);
         };
@@ -70371,59 +76498,57 @@ ${content}</tr>
       _oscSelectedImage = null;
       this.updateUrlImage(null);
       var viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(null);
+      if (!viewer.empty()) viewer.datum(null);
       viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
       context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
       return this.setStyles(context, null, true);
     },
     selectImage: function(context, imageKey) {
-      var d = this.cachedImage(imageKey);
-      _oscSelectedImage = d;
+      var d2 = this.cachedImage(imageKey);
+      _oscSelectedImage = d2;
       this.updateUrlImage(imageKey);
       var viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(d);
+      if (!viewer.empty()) viewer.datum(d2);
       this.setStyles(context, null, true);
       context.container().selectAll(".icon-sign").classed("currentView", false);
-      if (!d)
-        return this;
+      if (!d2) return this;
       var wrap2 = context.container().select(".photoviewer .kartaview-wrapper");
       var imageWrap = wrap2.selectAll(".kartaview-image-wrap");
       var attribution = wrap2.selectAll(".photo-attribution").text("");
-      wrap2.transition().duration(100).call(imgZoom.transform, identity2);
+      wrap2.transition().duration(100).call(imgZoom2.transform, identity2);
       imageWrap.selectAll(".kartaview-image").remove();
-      if (d) {
-        var sequence = _oscCache.sequences[d.sequence_id];
-        var r = sequence && sequence.rotation || 0;
-        imageWrap.append("img").attr("class", "kartaview-image").attr("src", apibase2 + "/" + d.imagePath).style("transform", "rotate(" + r + "deg)");
-        if (d.captured_by) {
-          attribution.append("a").attr("class", "captured_by").attr("target", "_blank").attr("href", "https://kartaview.org/user/" + encodeURIComponent(d.captured_by)).text("@" + d.captured_by);
+      if (d2) {
+        var sequence = _oscCache.sequences[d2.sequence_id];
+        var r2 = sequence && sequence.rotation || 0;
+        imageWrap.append("img").attr("class", "kartaview-image").attr("src", apibase2 + "/" + d2.imagePath).style("transform", "rotate(" + r2 + "deg)");
+        if (d2.captured_by) {
+          attribution.append("a").attr("class", "captured_by").attr("target", "_blank").attr("href", "https://kartaview.org/user/" + encodeURIComponent(d2.captured_by)).text("@" + d2.captured_by);
           attribution.append("span").text("|");
         }
-        if (d.captured_at) {
-          attribution.append("span").attr("class", "captured_at").text(localeDateString2(d.captured_at));
+        if (d2.captured_at) {
+          attribution.append("span").attr("class", "captured_at").text(localeDateString2(d2.captured_at));
           attribution.append("span").text("|");
         }
-        attribution.append("a").attr("class", "image-link").attr("target", "_blank").attr("href", "https://kartaview.org/details/" + d.sequence_id + "/" + d.sequence_index).text("kartaview.org");
+        attribution.append("a").attr("class", "image-link").attr("target", "_blank").attr("href", "https://kartaview.org/details/" + d2.sequence_id + "/" + d2.sequence_index).text("kartaview.org");
       }
       return this;
-      function localeDateString2(s) {
-        if (!s)
-          return null;
+      function localeDateString2(s2) {
+        if (!s2) return null;
         var options2 = { day: "numeric", month: "short", year: "numeric" };
-        var d2 = new Date(s);
-        if (isNaN(d2.getTime()))
-          return null;
-        return d2.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+        var d4 = new Date(s2);
+        if (isNaN(d4.getTime())) return null;
+        return d4.toLocaleDateString(_mainLocalizer.localeCode(), options2);
       }
     },
     getSelectedImage: function() {
       return _oscSelectedImage;
     },
-    getSequenceKeyForImage: function(d) {
-      return d && d.sequence_id;
+    getSequenceKeyForImage: function(d2) {
+      return d2 && d2.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);
@@ -70432,34 +76557,34 @@ ${content}</tr>
       var hoveredImageKey = hovered && hovered.key;
       var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
       var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
-      var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function(d) {
-        return d.key;
+      var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function(d2) {
+        return d2.key;
       }) || [];
       var viewer = context.container().select(".photoviewer");
       var selected = viewer.empty() ? void 0 : viewer.datum();
       var selectedImageKey = selected && selected.key;
       var selectedSequenceKey = this.getSequenceKeyForImage(selected);
       var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
-      var selectedImageKeys = selectedSequence && selectedSequence.images.map(function(d) {
-        return d.key;
+      var selectedImageKeys = selectedSequence && selectedSequence.images.map(function(d2) {
+        return d2.key;
       }) || [];
       var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
-      context.container().selectAll(".layer-kartaview .viewfield-group").classed("highlighted", function(d) {
-        return highlightedImageKeys.indexOf(d.key) !== -1;
-      }).classed("hovered", function(d) {
-        return d.key === hoveredImageKey;
-      }).classed("currentView", function(d) {
-        return d.key === selectedImageKey;
-      });
-      context.container().selectAll(".layer-kartaview .sequence").classed("highlighted", function(d) {
-        return d.properties.key === hoveredSequenceKey;
-      }).classed("currentView", function(d) {
-        return d.properties.key === selectedSequenceKey;
+      context.container().selectAll(".layer-kartaview .viewfield-group").classed("highlighted", function(d2) {
+        return highlightedImageKeys.indexOf(d2.key) !== -1;
+      }).classed("hovered", function(d2) {
+        return d2.key === hoveredImageKey;
+      }).classed("currentView", function(d2) {
+        return d2.key === selectedImageKey;
+      });
+      context.container().selectAll(".layer-kartaview .sequence").classed("highlighted", function(d2) {
+        return d2.properties.key === hoveredSequenceKey;
+      }).classed("currentView", function(d2) {
+        return d2.properties.key === selectedSequenceKey;
       });
       context.container().selectAll(".layer-kartaview .viewfield-group .viewfield").attr("d", viewfieldPath);
       function viewfieldPath() {
-        var d = this.parentNode.__data__;
-        if (d.pano && d.key !== selectedImageKey) {
+        var d2 = this.parentNode.__data__;
+        if (d2.pano && d2.key !== selectedImageKey) {
           return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
         } else {
           return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
@@ -70483,10 +76608,587 @@ ${content}</tr>
     }
   };
 
+  // modules/services/pannellum_photo.js
+  var pannellumViewerCSS = "pannellum/pannellum.css";
+  var pannellumViewerJS = "pannellum/pannellum.js";
+  var dispatch7 = dispatch_default("viewerChanged");
+  var _currScenes = [];
+  var _pannellumViewer;
+  var pannellum_photo_default = {
+    init: async function(context, selection2) {
+      selection2.append("div").attr("class", "photo-frame pannellum-frame").attr("id", "ideditor-pannellum-viewer").classed("hide", true).on("keydown", function(e3) {
+        e3.stopPropagation();
+      });
+      if (!window.pannellum) {
+        await this.loadPannellum(context);
+      }
+      const options2 = {
+        "default": { firstScene: "" },
+        scenes: {},
+        minHfov: 20
+      };
+      _pannellumViewer = window.pannellum.viewer("ideditor-pannellum-viewer", options2);
+      _pannellumViewer.on("mousedown", () => {
+        select_default2(window).on("pointermove.pannellum mousemove.pannellum", () => {
+          dispatch7.call("viewerChanged");
+        });
+      }).on("mouseup", () => {
+        select_default2(window).on("pointermove.pannellum mousemove.pannellum", null);
+      }).on("animatefinished", () => {
+        dispatch7.call("viewerChanged");
+      });
+      context.ui().photoviewer.on("resize.pannellum", () => {
+        _pannellumViewer.resize();
+      });
+      this.event = utilRebind(this, dispatch7, "on");
+      return this;
+    },
+    loadPannellum: function(context) {
+      const head = select_default2("head");
+      return Promise.all([
+        new Promise((resolve, reject) => {
+          head.selectAll("#ideditor-pannellum-viewercss").data([0]).enter().append("link").attr("id", "ideditor-pannellum-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(pannellumViewerCSS)).on("load.pannellum", resolve).on("error.pannellum", reject);
+        }),
+        new Promise((resolve, reject) => {
+          head.selectAll("#ideditor-pannellum-viewerjs").data([0]).enter().append("script").attr("id", "ideditor-pannellum-viewerjs").attr("crossorigin", "anonymous").attr("src", context.asset(pannellumViewerJS)).on("load.pannellum", resolve).on("error.pannellum", reject);
+        })
+      ]);
+    },
+    showPhotoFrame: function(context) {
+      const isHidden = context.selectAll(".photo-frame.pannellum-frame.hide").size();
+      if (isHidden) {
+        context.selectAll(".photo-frame:not(.pannellum-frame)").classed("hide", true);
+        context.selectAll(".photo-frame.pannellum-frame").classed("hide", false);
+      }
+      return this;
+    },
+    hidePhotoFrame: function(viewerContext) {
+      viewerContext.select("photo-frame.pannellum-frame").classed("hide", false);
+      return this;
+    },
+    selectPhoto: function(data, keepOrientation) {
+      const { key } = data;
+      if (!(key in _currScenes)) {
+        let newSceneOptions = {
+          showFullscreenCtrl: false,
+          autoLoad: false,
+          compass: false,
+          yaw: 0,
+          type: "equirectangular",
+          preview: data.preview_path,
+          panorama: data.image_path,
+          northOffset: data.ca
+        };
+        _currScenes.push(key);
+        _pannellumViewer.addScene(key, newSceneOptions);
+      }
+      let yaw = 0;
+      let pitch = 0;
+      if (keepOrientation) {
+        yaw = this.getYaw();
+        pitch = _pannellumViewer.getPitch();
+      }
+      _pannellumViewer.loadScene(key, pitch, yaw);
+      dispatch7.call("viewerChanged");
+      if (_currScenes.length > 3) {
+        const old_key = _currScenes.shift();
+        _pannellumViewer.removeScene(old_key);
+      }
+      _pannellumViewer.resize();
+      return this;
+    },
+    getYaw: function() {
+      return _pannellumViewer.getYaw();
+    }
+  };
+
+  // modules/services/vegbilder.js
+  var owsEndpoint = "https://www.vegvesen.no/kart/ogc/vegbilder_1_0/ows?";
+  var tileZoom2 = 14;
+  var tiler4 = utilTiler().zoomExtent([tileZoom2, tileZoom2]).skipNullIsland(true);
+  var dispatch8 = dispatch_default("loadedImages", "viewerChanged");
+  var directionEnum = Object.freeze({
+    forward: Symbol(0),
+    backward: Symbol(1)
+  });
+  var _planeFrame;
+  var _pannellumFrame;
+  var _currentFrame;
+  var _loadViewerPromise3;
+  var _vegbilderCache;
+  async function fetchAvailableLayers() {
+    var _a3, _b3, _c;
+    const params = {
+      service: "WFS",
+      request: "GetCapabilities",
+      version: "2.0.0"
+    };
+    const urlForRequest = owsEndpoint + utilQsString(params);
+    const response = await xml_default(urlForRequest);
+    const xPathSelector = "/wfs:WFS_Capabilities/wfs:FeatureTypeList/wfs:FeatureType/wfs:Name";
+    const regexMatcher = /^vegbilder_1_0:Vegbilder(?<image_type>_360)?_(?<year>\d{4})$/;
+    const NSResolver = response.createNSResolver(response);
+    const l2 = response.evaluate(
+      xPathSelector,
+      response,
+      NSResolver,
+      XPathResult.ANY_TYPE
+    );
+    let node;
+    const availableLayers = [];
+    while ((node = l2.iterateNext()) !== null) {
+      const match = (_a3 = node.textContent) == null ? void 0 : _a3.match(regexMatcher);
+      if (match) {
+        availableLayers.push({
+          name: match[0],
+          is_sphere: !!((_b3 = match.groups) == null ? void 0 : _b3.image_type),
+          year: parseInt((_c = match.groups) == null ? void 0 : _c.year, 10)
+        });
+      }
+    }
+    return availableLayers;
+  }
+  function filterAvailableLayers(photoContex) {
+    const fromDateString = photoContex.fromDate();
+    const toDateString = photoContex.toDate();
+    const fromYear = fromDateString ? new Date(fromDateString).getFullYear() : 2016;
+    const toYear = toDateString ? new Date(toDateString).getFullYear() : null;
+    const showsFlat = photoContex.showsFlat();
+    const showsPano = photoContex.showsPanoramic();
+    return Array.from(_vegbilderCache.wfslayers.values()).filter(({ layerInfo }) => layerInfo.year >= fromYear && (!toYear || layerInfo.year <= toYear) && (!layerInfo.is_sphere && showsFlat || layerInfo.is_sphere && showsPano));
+  }
+  function loadWFSLayers(projection2, margin, wfslayers) {
+    const tiles = tiler4.margin(margin).getTiles(projection2);
+    for (const cache of wfslayers) {
+      loadWFSLayer(projection2, cache, tiles);
+    }
+  }
+  function loadWFSLayer(projection2, cache, tiles) {
+    for (const [key, controller] of cache.inflight.entries()) {
+      const wanted = tiles.some((tile) => key === tile.id);
+      if (!wanted) {
+        controller.abort();
+        cache.inflight.delete(key);
+      }
+    }
+    Promise.all(tiles.map(
+      (tile) => loadTile2(cache, cache.layerInfo.name, tile)
+    )).then(() => orderSequences(projection2, cache));
+  }
+  async function loadTile2(cache, typename, tile) {
+    const bbox2 = tile.extent.bbox();
+    const tileid = tile.id;
+    if (cache.loaded.get(tileid) === true || cache.inflight.has(tileid)) return;
+    const params = {
+      service: "WFS",
+      request: "GetFeature",
+      version: "2.0.0",
+      typenames: typename,
+      bbox: [bbox2.minY, bbox2.minX, bbox2.maxY, bbox2.maxX].join(","),
+      outputFormat: "json"
+    };
+    const controller = new AbortController();
+    cache.inflight.set(tileid, controller);
+    const options2 = {
+      method: "GET",
+      signal: controller.signal
+    };
+    const urlForRequest = owsEndpoint + utilQsString(params);
+    let featureCollection;
+    try {
+      featureCollection = await json_default(urlForRequest, options2);
+    } catch {
+      cache.loaded.set(tileid, false);
+      return;
+    } finally {
+      cache.inflight.delete(tileid);
+    }
+    cache.loaded.set(tileid, true);
+    if (featureCollection.features.length === 0) {
+      return;
+    }
+    const features = featureCollection.features.map((feature3) => {
+      const loc = feature3.geometry.coordinates;
+      const key = feature3.id;
+      const properties = feature3.properties;
+      const {
+        RETNING: ca,
+        TIDSPUNKT: captured_at,
+        URL: image_path,
+        URLPREVIEW: preview_path,
+        BILDETYPE: image_type,
+        METER: metering,
+        FELTKODE: lane_code
+      } = properties;
+      const lane_number = parseInt(lane_code.match(/^[0-9]+/)[0], 10);
+      const direction = lane_number % 2 === 0 ? directionEnum.backward : directionEnum.forward;
+      const data = {
+        loc,
+        key,
+        ca,
+        image_path,
+        preview_path,
+        road_reference: roadReference(properties),
+        metering,
+        lane_code,
+        direction,
+        captured_at: new Date(captured_at),
+        is_sphere: image_type === "360"
+      };
+      cache.points.set(key, data);
+      return {
+        minX: loc[0],
+        minY: loc[1],
+        maxX: loc[0],
+        maxY: loc[1],
+        data
+      };
+    });
+    _vegbilderCache.rtree.load(features);
+    dispatch8.call("loadedImages");
+  }
+  function orderSequences(projection2, cache) {
+    const { points } = cache;
+    const grouped = Array.from(points.values()).reduce((grouped2, image) => {
+      const key = image.road_reference;
+      if (grouped2.has(key)) {
+        grouped2.get(key).push(image);
+      } else {
+        grouped2.set(key, [image]);
+      }
+      return grouped2;
+    }, /* @__PURE__ */ new Map());
+    const imageSequences = Array.from(grouped.values()).reduce((imageSequences2, imageGroup) => {
+      imageGroup.sort((a2, b2) => {
+        if (a2.captured_at.valueOf() > b2.captured_at.valueOf()) {
+          return 1;
+        } else if (a2.captured_at.valueOf() < b2.captured_at.valueOf()) {
+          return -1;
+        } else {
+          const { direction } = a2;
+          if (direction === directionEnum.forward) {
+            return a2.metering - b2.metering;
+          } else {
+            return b2.metering - a2.metering;
+          }
+        }
+      });
+      let imageSequence = [imageGroup[0]];
+      let angle2 = null;
+      for (const [lastImage, image] of pairs(imageGroup)) {
+        if (lastImage.ca === null) {
+          const b2 = projection2(lastImage.loc);
+          const a2 = projection2(image.loc);
+          if (!geoVecEqual(a2, b2)) {
+            angle2 = geoVecAngle(a2, b2);
+            angle2 *= 180 / Math.PI;
+            angle2 -= 90;
+            angle2 = angle2 >= 0 ? angle2 : angle2 + 360;
+          }
+          lastImage.ca = angle2;
+        }
+        if (image.direction === lastImage.direction && image.captured_at.valueOf() - lastImage.captured_at.valueOf() <= 2e4) {
+          imageSequence.push(image);
+        } else {
+          imageSequences2.push(imageSequence);
+          imageSequence = [image];
+        }
+      }
+      imageSequences2.push(imageSequence);
+      return imageSequences2;
+    }, []);
+    cache.sequences = imageSequences.map((images) => {
+      const sequence = {
+        images,
+        key: images[0].key,
+        geometry: {
+          type: "LineString",
+          coordinates: images.map((image) => image.loc)
+        }
+      };
+      for (const image of images) {
+        _vegbilderCache.image2sequence_map.set(image.key, sequence);
+      }
+      return sequence;
+    });
+  }
+  function roadReference(properties) {
+    const {
+      FYLKENUMMER: county_number,
+      VEGKATEGORI: road_class,
+      VEGSTATUS: road_status,
+      VEGNUMMER: road_number,
+      STREKNING: section,
+      DELSTREKNING: subsection,
+      HP: parcel,
+      KRYSSDEL: junction_part,
+      SIDEANLEGGSDEL: services_part,
+      ANKERPUNKT: anker_point,
+      AAR: year
+    } = properties;
+    let reference;
+    if (year >= 2020) {
+      reference = "".concat(road_class).concat(road_status).concat(road_number, " S").concat(section, "D").concat(subsection);
+      if (junction_part) {
+        reference = "".concat(reference, " M").concat(anker_point, " KD").concat(junction_part);
+      } else if (services_part) {
+        reference = "".concat(reference, " M").concat(anker_point, " SD").concat(services_part);
+      }
+    } else {
+      reference = "".concat(county_number).concat(road_class).concat(road_status).concat(road_number, " HP").concat(parcel);
+    }
+    return reference;
+  }
+  function localeTimestamp(date) {
+    const options2 = {
+      day: "2-digit",
+      month: "2-digit",
+      year: "numeric",
+      hour: "numeric",
+      minute: "numeric",
+      second: "numeric"
+    };
+    return date.toLocaleString(_mainLocalizer.localeCode(), options2);
+  }
+  function partitionViewport3(projection2) {
+    const zoom = geoScaleToZoom(projection2.scale());
+    const roundZoom = Math.ceil(zoom * 2) / 2 + 2.5;
+    const tiler8 = utilTiler().zoomExtent([roundZoom, roundZoom]);
+    return tiler8.getTiles(projection2).map((tile) => tile.extent);
+  }
+  function searchLimited3(limit, projection2, rtree) {
+    limit != null ? limit : limit = 5;
+    return partitionViewport3(projection2).reduce((result, extent) => {
+      const found = rtree.search(extent.bbox()).slice(0, limit).map((d2) => d2.data);
+      return result.concat(found);
+    }, []);
+  }
+  var vegbilder_default = {
+    init: function() {
+      this.event = utilRebind(this, dispatch8, "on");
+    },
+    reset: async function() {
+      if (_vegbilderCache) {
+        for (const layer of _vegbilderCache.wfslayers.values()) {
+          for (const controller of layer.inflight.values()) {
+            controller.abort();
+          }
+        }
+      }
+      _vegbilderCache = {
+        wfslayers: /* @__PURE__ */ new Map(),
+        rtree: new RBush(),
+        image2sequence_map: /* @__PURE__ */ new Map()
+      };
+      const availableLayers = await fetchAvailableLayers();
+      const { wfslayers } = _vegbilderCache;
+      for (const layerInfo of availableLayers) {
+        const cache = {
+          layerInfo,
+          loaded: /* @__PURE__ */ new Map(),
+          inflight: /* @__PURE__ */ new Map(),
+          points: /* @__PURE__ */ new Map(),
+          sequences: []
+        };
+        wfslayers.set(layerInfo.name, cache);
+      }
+    },
+    images: function(projection2) {
+      const limit = 5;
+      return searchLimited3(limit, projection2, _vegbilderCache.rtree);
+    },
+    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 seen = /* @__PURE__ */ new Set();
+      const line_strings = [];
+      for (const { data } of _vegbilderCache.rtree.search(bbox2)) {
+        const sequence = _vegbilderCache.image2sequence_map.get(data.key);
+        if (!sequence) continue;
+        const { key, geometry, images } = sequence;
+        if (seen.has(key)) continue;
+        seen.add(key);
+        const line = {
+          type: "LineString",
+          coordinates: geometry.coordinates,
+          key,
+          images
+        };
+        line_strings.push(line);
+      }
+      return line_strings;
+    },
+    cachedImage: function(key) {
+      for (const { points } of _vegbilderCache.wfslayers.values()) {
+        if (points.has(key)) return points.get(key);
+      }
+    },
+    getSequenceForImage: function(image) {
+      return _vegbilderCache == null ? void 0 : _vegbilderCache.image2sequence_map.get(image == null ? void 0 : image.key);
+    },
+    loadImages: async function(context, margin) {
+      if (!_vegbilderCache) {
+        await this.reset();
+      }
+      margin != null ? margin : margin = 1;
+      const wfslayers = filterAvailableLayers(context.photos());
+      loadWFSLayers(context.projection, margin, wfslayers);
+    },
+    photoFrame: function() {
+      return _currentFrame;
+    },
+    ensureViewerLoaded: function(context) {
+      if (_loadViewerPromise3) return _loadViewerPromise3;
+      const step = (stepBy) => () => {
+        const viewer = context.container().select(".photoviewer");
+        const selected = viewer.empty() ? void 0 : viewer.datum();
+        if (!selected) return;
+        const sequence = this.getSequenceForImage(selected);
+        const nextIndex = sequence.images.indexOf(selected) + stepBy;
+        const nextImage = sequence.images[nextIndex];
+        if (!nextImage) return;
+        context.map().centerEase(nextImage.loc);
+        this.selectImage(context, nextImage.key, true);
+      };
+      const wrap2 = context.container().select(".photoviewer").selectAll(".vegbilder-wrapper").data([0]);
+      const wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper vegbilder-wrapper").classed("hide", true);
+      wrapEnter.append("div").attr("class", "photo-attribution fillD");
+      const controlsEnter = wrapEnter.append("div").attr("class", "photo-controls-wrap").append("div").attr("class", "photo-controls");
+      controlsEnter.append("button").on("click.back", step(-1)).text("\u25C4");
+      controlsEnter.append("button").on("click.forward", step(1)).text("\u25BA");
+      _loadViewerPromise3 = Promise.all([
+        pannellum_photo_default.init(context, wrapEnter),
+        plane_photo_default.init(context, wrapEnter)
+      ]).then(([pannellumPhotoFrame, planePhotoFrame]) => {
+        _pannellumFrame = pannellumPhotoFrame;
+        _pannellumFrame.event.on("viewerChanged", () => dispatch8.call("viewerChanged"));
+        _planeFrame = planePhotoFrame;
+        _planeFrame.event.on("viewerChanged", () => dispatch8.call("viewerChanged"));
+      });
+      return _loadViewerPromise3;
+    },
+    selectImage: function(context, key, keepOrientation) {
+      const d2 = this.cachedImage(key);
+      this.updateUrlImage(key);
+      const viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) {
+        viewer.datum(d2);
+      }
+      this.setStyles(context, null, true);
+      if (!d2) return this;
+      const wrap2 = context.container().select(".photoviewer .vegbilder-wrapper");
+      const attribution = wrap2.selectAll(".photo-attribution").text("");
+      if (d2.captured_at) {
+        attribution.append("span").attr("class", "captured_at").text(localeTimestamp(d2.captured_at));
+      }
+      attribution.append("a").attr("target", "_blank").attr("href", "https://vegvesen.no").call(_t.append("vegbilder.publisher"));
+      attribution.append("a").attr("target", "_blank").attr("href", "https://vegbilder.atlas.vegvesen.no/?year=".concat(d2.captured_at.getFullYear(), "&lat=").concat(d2.loc[1], "&lng=").concat(d2.loc[0], "&view=image&imageId=").concat(d2.key)).call(_t.append("vegbilder.view_on"));
+      _currentFrame = d2.is_sphere ? _pannellumFrame : _planeFrame;
+      _currentFrame.selectPhoto(d2, keepOrientation).showPhotoFrame(wrap2);
+      return this;
+    },
+    showViewer: function(context) {
+      const viewer = context.container().select(".photoviewer").classed("hide", false);
+      const isHidden = viewer.selectAll(".photo-wrapper.vegbilder-wrapper.hide").size();
+      if (isHidden) {
+        viewer.selectAll(".photo-wrapper:not(.vegbilder-wrapper)").classed("hide", true);
+        viewer.selectAll(".photo-wrapper.vegbilder-wrapper").classed("hide", false);
+      }
+      return this;
+    },
+    hideViewer: function(context) {
+      this.updateUrlImage(null);
+      const viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) viewer.datum(null);
+      viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
+      context.container().selectAll(".viewfield-group, .sequence").classed("currentView", false);
+      return this.setStyles(context, null, true);
+    },
+    // 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) {
+      var _a3, _b3;
+      if (reset) {
+        context.container().selectAll(".viewfield-group").classed("highlighted", false).classed("hovered", false).classed("currentView", false);
+        context.container().selectAll(".sequence").classed("highlighted", false).classed("currentView", false);
+      }
+      const hoveredImageKey = hovered == null ? void 0 : hovered.key;
+      const hoveredSequence = this.getSequenceForImage(hovered);
+      const hoveredSequenceKey = hoveredSequence == null ? void 0 : hoveredSequence.key;
+      const hoveredImageKeys = (_a3 = hoveredSequence == null ? void 0 : hoveredSequence.images.map((d2) => d2.key)) != null ? _a3 : [];
+      const viewer = context.container().select(".photoviewer");
+      const selected = viewer.empty() ? void 0 : viewer.datum();
+      const selectedImageKey = selected == null ? void 0 : selected.key;
+      const selectedSequence = this.getSequenceForImage(selected);
+      const selectedSequenceKey = selectedSequence == null ? void 0 : selectedSequence.key;
+      const selectedImageKeys = (_b3 = selectedSequence == null ? void 0 : selectedSequence.images.map((d2) => d2.key)) != null ? _b3 : [];
+      const highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
+      context.container().selectAll(".layer-vegbilder .viewfield-group").classed("highlighted", (d2) => highlightedImageKeys.indexOf(d2.key) !== -1).classed("hovered", (d2) => d2.key === hoveredImageKey).classed("currentView", (d2) => d2.key === selectedImageKey);
+      context.container().selectAll(".layer-vegbilder .sequence").classed("highlighted", (d2) => d2.key === hoveredSequenceKey).classed("currentView", (d2) => d2.key === selectedSequenceKey);
+      context.container().selectAll(".layer-vegbilder .viewfield-group .viewfield").attr("d", viewfieldPath);
+      function viewfieldPath() {
+        const d2 = this.parentNode.__data__;
+        if (d2.is_sphere && d2.key !== selectedImageKey) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
+      }
+      return this;
+    },
+    updateUrlImage: function(key) {
+      if (!window.mocha) {
+        const hash = utilStringQs(window.location.hash);
+        if (key) {
+          hash.photo = "vegbilder/" + key;
+        } else {
+          delete hash.photo;
+        }
+        window.location.replace("#" + utilQsString(hash, true));
+      }
+    },
+    validHere: function(extent) {
+      const bbox2 = Object.values(extent.bbox());
+      return iso1A2Codes(bbox2).includes("NO");
+    },
+    cache: function() {
+      return _vegbilderCache;
+    }
+  };
+
   // node_modules/osm-auth/src/osm-auth.mjs
-  var import_store = __toESM(require_store_legacy(), 1);
-  function osmAuth(o) {
+  function osmAuth(o2) {
     var oauth2 = {};
+    var _store = null;
+    try {
+      _store = window.localStorage;
+    } catch (e3) {
+      var _mock = /* @__PURE__ */ new Map();
+      _store = {
+        isMocked: true,
+        hasItem: (k2) => _mock.has(k2),
+        getItem: (k2) => _mock.get(k2),
+        setItem: (k2, v2) => _mock.set(k2, v2),
+        removeItem: (k2) => _mock.delete(k2),
+        clear: () => _mock.clear()
+      };
+    }
+    function token(k2, v2) {
+      var key = o2.url + k2;
+      if (arguments.length === 1) {
+        var val = _store.getItem(key) || "";
+        return val.replace(/"/g, "");
+      } else if (arguments.length === 2) {
+        if (v2) {
+          return _store.setItem(key, v2);
+        } else {
+          return _store.removeItem(key);
+        }
+      }
+    }
     oauth2.authenticated = function() {
       return !!token("oauth2_access_token");
     };
@@ -70503,50 +77205,106 @@ ${content}</tr>
         return;
       }
       oauth2.logout();
-      var url = o.url + "/oauth2/authorize?" + utilQsString2({
-        client_id: o.client_id,
-        redirect_uri: o.redirect_uri,
+      _preopenPopup(function(error, popup) {
+        if (error) {
+          callback(error);
+        } else {
+          _generatePkceChallenge(function(pkce) {
+            _authenticate(pkce, popup, callback);
+          });
+        }
+      });
+    };
+    oauth2.authenticateAsync = function() {
+      if (oauth2.authenticated()) {
+        return Promise.resolve(oauth2);
+      }
+      oauth2.logout();
+      return new Promise((resolve, reject) => {
+        var errback = (err, result) => {
+          if (err) {
+            reject(err);
+          } else {
+            resolve(result);
+          }
+        };
+        _preopenPopup((error, popup) => {
+          if (error) {
+            errback(error);
+          } else {
+            _generatePkceChallenge((pkce) => _authenticate(pkce, popup, errback));
+          }
+        });
+      });
+    };
+    function _preopenPopup(callback) {
+      if (o2.singlepage) {
+        callback(null, void 0);
+        return;
+      }
+      var w2 = 550;
+      var h2 = 610;
+      var settings = [
+        ["width", w2],
+        ["height", h2],
+        ["left", window.screen.width / 2 - w2 / 2],
+        ["top", window.screen.height / 2 - h2 / 2]
+      ].map(function(x2) {
+        return x2.join("=");
+      }).join(",");
+      var popup = window.open("about:blank", "oauth_window", settings);
+      if (popup) {
+        callback(null, popup);
+      } else {
+        var error = new Error("Popup was blocked");
+        error.status = "popup-blocked";
+        callback(error);
+      }
+    }
+    function _authenticate(pkce, popup, callback) {
+      var state = generateState();
+      var url = o2.url + "/oauth2/authorize?" + utilQsString2({
+        client_id: o2.client_id,
+        redirect_uri: o2.redirect_uri,
         response_type: "code",
-        scope: o.scope
-      });
-      if (!o.singlepage) {
-        var w = 600;
-        var h = 550;
-        var settings = [
-          ["width", w],
-          ["height", h],
-          ["left", screen.width / 2 - w / 2],
-          ["top", screen.height / 2 - h / 2]
-        ].map(function(x) {
-          return x.join("=");
-        }).join(",");
-        var popup = window.open("about:blank", "oauth_window", settings);
+        scope: o2.scope,
+        state,
+        code_challenge: pkce.code_challenge,
+        code_challenge_method: pkce.code_challenge_method,
+        locale: o2.locale || ""
+      });
+      if (o2.singlepage) {
+        if (_store.isMocked) {
+          var error = new Error("localStorage unavailable, but required in singlepage mode");
+          error.status = "pkce-localstorage-unavailable";
+          callback(error);
+          return;
+        }
+        var params = utilStringQs2(window.location.search.slice(1));
+        if (params.code) {
+          oauth2.bootstrapToken(params.code, callback);
+        } else {
+          token("oauth2_state", state);
+          token("oauth2_pkce_code_verifier", pkce.code_verifier);
+          window.location = url;
+        }
+      } else {
         oauth2.popupWindow = popup;
         popup.location = url;
-        if (!popup) {
-          var error = new Error("Popup was blocked");
-          error.status = "popup-blocked";
-          throw error;
-        }
       }
       window.authComplete = function(url2) {
-        var params = utilStringQs2(url2.split("?")[1]);
-        getAccessToken(params.code);
+        var params2 = utilStringQs2(url2.split("?")[1]);
+        if (params2.state !== state) {
+          var error2 = new Error("Invalid state");
+          error2.status = "invalid-state";
+          callback(error2);
+          return;
+        }
+        _getAccessToken(params2.code, pkce.code_verifier, accessTokenDone);
         delete window.authComplete;
       };
-      function getAccessToken(auth_code) {
-        var url2 = o.url + "/oauth2/token?" + utilQsString2({
-          client_id: o.client_id,
-          grant_type: "authorization_code",
-          code: auth_code,
-          redirect_uri: o.redirect_uri,
-          client_secret: o.client_secret
-        });
-        oauth2.rawxhr("POST", url2, null, null, null, accessTokenDone);
-        o.loading();
-      }
       function accessTokenDone(err, xhr) {
-        o.done();
+        o2.done();
         if (err) {
           callback(err);
           return;
@@ -70555,7 +77313,18 @@ ${content}</tr>
         token("oauth2_access_token", access_token.access_token);
         callback(null, oauth2);
       }
-    };
+    }
+    function _getAccessToken(auth_code, code_verifier, accessTokenDone) {
+      var url = o2.url + "/oauth2/token?" + utilQsString2({
+        client_id: o2.client_id,
+        redirect_uri: o2.redirect_uri,
+        grant_type: "authorization_code",
+        code: auth_code,
+        code_verifier
+      });
+      oauth2.rawxhr("POST", url, null, null, null, accessTokenDone);
+      o2.loading();
+    }
     oauth2.bringPopupWindowToFront = function() {
       var broughtPopupToFront = false;
       try {
@@ -70568,19 +77337,20 @@ ${content}</tr>
       return broughtPopupToFront;
     };
     oauth2.bootstrapToken = function(auth_code, callback) {
-      function getAccessToken(auth_code2) {
-        var url = o.url + "/oauth2/token?" + utilQsString2({
-          client_id: o.client_id,
-          grant_type: "authorization_code",
-          code: auth_code2,
-          redirect_uri: o.redirect_uri,
-          client_secret: o.client_secret
-        });
-        oauth2.rawxhr("POST", url, null, null, null, accessTokenDone);
-        o.loading();
+      var state = token("oauth2_state");
+      token("oauth2_state", "");
+      var params = utilStringQs2(window.location.search.slice(1));
+      if (params.state !== state) {
+        var error = new Error("Invalid state");
+        error.status = "invalid-state";
+        callback(error);
+        return;
       }
+      var code_verifier = token("oauth2_pkce_code_verifier");
+      token("oauth2_pkce_code_verifier", "");
+      _getAccessToken(auth_code, code_verifier, accessTokenDone);
       function accessTokenDone(err, xhr) {
-        o.done();
+        o2.done();
         if (err) {
           callback(err);
           return;
@@ -70589,22 +77359,40 @@ ${content}</tr>
         token("oauth2_access_token", access_token.access_token);
         callback(null, oauth2);
       }
-      getAccessToken(auth_code);
+    };
+    oauth2.fetch = function(resource, options2) {
+      if (oauth2.authenticated()) {
+        return _doFetch();
+      } else {
+        if (o2.auto) {
+          return oauth2.authenticateAsync().then(_doFetch);
+        } else {
+          return Promise.reject(new Error("not authenticated"));
+        }
+      }
+      function _doFetch() {
+        options2 = options2 || {};
+        if (!options2.headers) {
+          options2.headers = { "Content-Type": "application/x-www-form-urlencoded" };
+        }
+        options2.headers.Authorization = "Bearer " + token("oauth2_access_token");
+        return fetch(resource, options2);
+      }
     };
     oauth2.xhr = function(options2, callback) {
       if (oauth2.authenticated()) {
-        return run();
+        return _doXHR();
       } else {
-        if (o.auto) {
-          oauth2.authenticate(run);
+        if (o2.auto) {
+          oauth2.authenticate(_doXHR);
           return;
         } else {
           callback("not authenticated", null);
           return;
         }
       }
-      function run() {
-        var url = options2.prefix !== false ? o.url + options2.path : options2.path;
+      function _doXHR() {
+        var url = options2.prefix !== false ? o2.apiUrl + options2.path : options2.path;
         return oauth2.rawxhr(
           options2.method,
           url,
@@ -70639,12 +77427,11 @@ ${content}</tr>
           }
         }
       };
-      xhr.onerror = function(e) {
-        callback(e, null);
+      xhr.onerror = function(e3) {
+        callback(e3, null);
       };
       xhr.open(method, url, true);
-      for (var h in headers)
-        xhr.setRequestHeader(h, headers[h]);
+      for (var h2 in headers) xhr.setRequestHeader(h2, headers[h2]);
       xhr.send(data);
       return xhr;
     };
@@ -70655,81 +77442,115 @@ ${content}</tr>
       return oauth2;
     };
     oauth2.options = function(val) {
-      if (!arguments.length)
-        return o;
-      o = val;
-      o.url = o.url || "https://www.openstreetmap.org";
-      o.auto = o.auto || false;
-      o.singlepage = o.singlepage || false;
-      o.loading = o.loading || function() {
-      };
-      o.done = o.done || function() {
+      if (!arguments.length) return o2;
+      o2 = val;
+      o2.apiUrl = o2.apiUrl || "https://api.openstreetmap.org";
+      o2.url = o2.url || "https://www.openstreetmap.org";
+      o2.auto = o2.auto || false;
+      o2.singlepage = o2.singlepage || false;
+      o2.loading = o2.loading || function() {
       };
-      return oauth2.preauth(o);
-    };
-    var token;
-    if (import_store.default.enabled) {
-      token = function(x, y) {
-        if (arguments.length === 1)
-          return import_store.default.get(o.url + x);
-        else if (arguments.length === 2)
-          return import_store.default.set(o.url + x, y);
-      };
-    } else {
-      var storage = {};
-      token = function(x, y) {
-        if (arguments.length === 1)
-          return storage[o.url + x];
-        else if (arguments.length === 2)
-          return storage[o.url + x] = y;
+      o2.done = o2.done || function() {
       };
-    }
-    oauth2.options(o);
+      return oauth2.preauth(o2);
+    };
+    oauth2.options(o2);
     return oauth2;
   }
   function utilQsString2(obj) {
-    return Object.keys(obj).sort().map(function(key) {
+    return Object.keys(obj).filter(function(key) {
+      return obj[key] !== void 0;
+    }).sort().map(function(key) {
       return encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]);
     }).join("&");
   }
-  function utilStringQs2(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("=");
+  function utilStringQs2(str) {
+    var i3 = 0;
+    while (i3 < str.length && (str[i3] === "?" || str[i3] === "#")) i3++;
+    str = str.slice(i3);
+    return str.split("&").reduce(function(obj, pair3) {
+      var parts = pair3.split("=");
       if (parts.length === 2) {
         obj[parts[0]] = decodeURIComponent(parts[1]);
       }
       return obj;
     }, {});
   }
+  function supportsWebCryptoAPI() {
+    return window && window.crypto && window.crypto.getRandomValues && window.crypto.subtle && window.crypto.subtle.digest;
+  }
+  function _generatePkceChallenge(callback) {
+    var code_verifier;
+    if (supportsWebCryptoAPI()) {
+      var random = window.crypto.getRandomValues(new Uint8Array(32));
+      code_verifier = base64(random.buffer);
+      var verifier = Uint8Array.from(Array.from(code_verifier).map(function(char) {
+        return char.charCodeAt(0);
+      }));
+      window.crypto.subtle.digest("SHA-256", verifier).then(function(hash) {
+        var code_challenge = base64(hash);
+        callback({
+          code_challenge,
+          code_verifier,
+          code_challenge_method: "S256"
+        });
+      });
+    } else {
+      var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+      code_verifier = "";
+      for (var i3 = 0; i3 < 64; i3++) {
+        code_verifier += chars[Math.floor(Math.random() * chars.length)];
+      }
+      callback({
+        code_verifier,
+        code_challenge: code_verifier,
+        code_challenge_method: "plain"
+      });
+    }
+  }
+  function generateState() {
+    var state;
+    if (supportsWebCryptoAPI()) {
+      var random = window.crypto.getRandomValues(new Uint8Array(32));
+      state = base64(random.buffer);
+    } else {
+      var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+      state = "";
+      for (var i3 = 0; i3 < 64; i3++) {
+        state += chars[Math.floor(Math.random() * chars.length)];
+      }
+    }
+    return state;
+  }
+  function base64(buffer) {
+    return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/[=]/g, "");
+  }
 
   // modules/services/osm.js
-  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 dispatch9 = dispatch_default("apiStatusChange", "authLoading", "authDone", "change", "loading", "loaded", "loadedNotes");
+  var urlroot = osmApiConnections[0].url;
+  var apiUrlroot = osmApiConnections[0].apiUrl || urlroot;
   var redirectPath = window.location.origin + window.location.pathname;
   var oauth = osmAuth({
     url: urlroot,
-    client_id: "0tmNTmd0Jo1dQp4AUmMBLtGiD9YpMuXzHefitcuVStc",
-    client_secret: "BTlNrNxIPitHdL4sP2clHw5KLoee9aKkA7dQbc0Bj7Q",
+    apiUrl: apiUrlroot,
+    client_id: osmApiConnections[0].client_id,
     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() };
+  var _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new RBush() };
+  var _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new RBush() };
   var _userCache = { toLoad: {}, user: {} };
   var _cachedApiStatus;
   var _changeset = {};
   var _deferred = /* @__PURE__ */ new Set();
   var _connectionID = 1;
-  var _tileZoom4 = 16;
+  var _tileZoom3 = 16;
   var _noteZoom = 12;
   var _rateLimitError;
   var _userChangesets;
@@ -70737,12 +77558,12 @@ ${content}</tr>
   var _off;
   var _maxWayNodes = 2e3;
   function authLoading() {
-    dispatch7.call("authLoading");
+    dispatch9.call("authLoading");
   }
   function authDone() {
-    dispatch7.call("authDone");
+    dispatch9.call("authDone");
   }
-  function abortRequest5(controllerOrXHR) {
+  function abortRequest4(controllerOrXHR) {
     if (controllerOrXHR) {
       controllerOrXHR.abort();
     }
@@ -70750,44 +77571,42 @@ ${content}</tr>
   function hasInflightRequests(cache) {
     return Object.keys(cache.inflight).length;
   }
-  function abortUnwantedRequests4(cache, visibleTiles) {
-    Object.keys(cache.inflight).forEach(function(k) {
-      if (cache.toLoad[k])
-        return;
+  function abortUnwantedRequests3(cache, visibleTiles) {
+    Object.keys(cache.inflight).forEach(function(k2) {
+      if (cache.toLoad[k2]) return;
       if (visibleTiles.find(function(tile) {
-        return k === tile.id;
-      }))
-        return;
-      abortRequest5(cache.inflight[k]);
-      delete cache.inflight[k];
+        return k2 === tile.id;
+      })) return;
+      abortRequest4(cache.inflight[k2]);
+      delete cache.inflight[k2];
     });
   }
   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");
     var nodes = new Array(elems.length);
-    for (var i2 = 0, l = elems.length; i2 < l; i2++) {
-      nodes[i2] = "n" + elems[i2].attributes.ref.value;
+    for (var i3 = 0, l2 = elems.length; i3 < l2; i3++) {
+      nodes[i3] = "n" + elems[i3].attributes.ref.value;
     }
     return nodes;
   }
   function getNodesJSON(obj) {
     var elems = obj.nodes;
     var nodes = new Array(elems.length);
-    for (var i2 = 0, l = elems.length; i2 < l; i2++) {
-      nodes[i2] = "n" + elems[i2];
+    for (var i3 = 0, l2 = elems.length; i3 < l2; i3++) {
+      nodes[i3] = "n" + elems[i3];
     }
     return nodes;
   }
   function getTags(obj) {
     var elems = obj.getElementsByTagName("tag");
     var tags = {};
-    for (var i2 = 0, l = elems.length; i2 < l; i2++) {
-      var attrs = elems[i2].attributes;
+    for (var i3 = 0, l2 = elems.length; i3 < l2; i3++) {
+      var attrs = elems[i3].attributes;
       tags[attrs.k.value] = attrs.v.value;
     }
     return tags;
@@ -70795,9 +77614,9 @@ ${content}</tr>
   function getMembers(obj) {
     var elems = obj.getElementsByTagName("member");
     var members = new Array(elems.length);
-    for (var i2 = 0, l = elems.length; i2 < l; i2++) {
-      var attrs = elems[i2].attributes;
-      members[i2] = {
+    for (var i3 = 0, l2 = elems.length; i3 < l2; i3++) {
+      var attrs = elems[i3].attributes;
+      members[i3] = {
         id: attrs.type.value[0] + attrs.ref.value,
         type: attrs.type.value,
         role: attrs.role.value
@@ -70808,9 +77627,9 @@ ${content}</tr>
   function getMembersJSON(obj) {
     var elems = obj.members;
     var members = new Array(elems.length);
-    for (var i2 = 0, l = elems.length; i2 < l; i2++) {
-      var attrs = elems[i2];
-      members[i2] = {
+    for (var i3 = 0, l2 = elems.length; i3 < l2; i3++) {
+      var attrs = elems[i3];
+      members[i3] = {
         id: attrs.type[0] + attrs.ref,
         type: attrs.type,
         role: attrs.role
@@ -70823,16 +77642,15 @@ ${content}</tr>
   }
   function parseComments(comments) {
     var parsedComments = [];
-    for (var i2 = 0; i2 < comments.length; i2++) {
-      var comment = comments[i2];
+    for (var i3 = 0; i3 < comments.length; i3++) {
+      var comment = comments[i3];
       if (comment.nodeName === "comment") {
         var childNodes = comment.childNodes;
         var parsedComment = {};
         for (var j2 = 0; j2 < childNodes.length; j2++) {
           var node = childNodes[j2];
           var nodeName = node.nodeName;
-          if (nodeName === "#text")
-            continue;
+          if (nodeName === "#text") continue;
           parsedComment[nodeName] = node.textContent;
           if (nodeName === "uid") {
             var uid = node.textContent;
@@ -70867,7 +77685,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
       });
     },
@@ -70914,32 +77732,27 @@ ${content}</tr>
       return callback({ message: "No JSON", status: -1 });
     }
     var json = payload;
-    if (typeof json !== "object")
-      json = JSON.parse(payload);
-    if (!json.elements)
-      return callback({ message: "No JSON", status: -1 });
+    if (typeof json !== "object") json = JSON.parse(payload);
+    if (!json.elements) return callback({ message: "No JSON", status: -1 });
     var children2 = json.elements;
     var handle = window.requestIdleCallback(function() {
       _deferred.delete(handle);
       var results = [];
       var result;
-      for (var i2 = 0; i2 < children2.length; i2++) {
-        result = parseChild(children2[i2]);
-        if (result)
-          results.push(result);
+      for (var i3 = 0; i3 < children2.length; i3++) {
+        result = parseChild(children2[i3]);
+        if (result) results.push(result);
       }
       callback(null, results);
     });
     _deferred.add(handle);
     function parseChild(child) {
       var parser3 = jsonparsers[child.type];
-      if (!parser3)
-        return null;
+      if (!parser3) return null;
       var uid;
       uid = osmEntity.id.fromOSM(child.type, child.id);
       if (options2.skipSeen) {
-        if (_tileCache.seen[uid])
-          return null;
+        if (_tileCache.seen[uid]) return null;
         _tileCache.seen[uid] = true;
       }
       return parser3(child, uid);
@@ -70951,19 +77764,16 @@ ${content}</tr>
       return callback({ message: "No JSON", status: -1 });
     }
     var json = payload;
-    if (typeof json !== "object")
-      json = JSON.parse(payload);
-    if (!json.users && !json.user)
-      return callback({ message: "No JSON", status: -1 });
+    if (typeof json !== "object") json = JSON.parse(payload);
+    if (!json.users && !json.user) return callback({ message: "No JSON", status: -1 });
     var objs = json.users || [json];
     var handle = window.requestIdleCallback(function() {
       _deferred.delete(handle);
       var results = [];
       var result;
-      for (var i2 = 0; i2 < objs.length; i2++) {
-        result = parseObj(objs[i2]);
-        if (result)
-          results.push(result);
+      for (var i3 = 0; i3 < objs.length; i3++) {
+        result = parseObj(objs[i3]);
+        if (result) results.push(result);
       }
       callback(null, results);
     });
@@ -71029,20 +77839,23 @@ ${content}</tr>
       var props = {};
       props.id = uid;
       props.loc = getLoc(attrs);
-      var coincident = false;
-      var epsilon3 = 1e-5;
-      do {
-        if (coincident) {
-          props.loc = geoVecAdd(props.loc, [epsilon3, epsilon3]);
-        }
-        var bbox = geoExtent(props.loc).bbox();
-        coincident = _noteCache.rtree.search(bbox).length;
-      } while (coincident);
-      for (var i2 = 0; i2 < childNodes.length; i2++) {
-        var node = childNodes[i2];
+      if (!_noteCache.note[uid]) {
+        let coincident = false;
+        const epsilon3 = 1e-5;
+        do {
+          if (coincident) {
+            props.loc = geoVecAdd(props.loc, [epsilon3, epsilon3]);
+          }
+          const bbox2 = geoExtent(props.loc).bbox();
+          coincident = _noteCache.rtree.search(bbox2).length;
+        } while (coincident);
+      } else {
+        props.loc = _noteCache.note[uid].loc;
+      }
+      for (var i3 = 0; i3 < childNodes.length; i3++) {
+        var node = childNodes[i3];
         var nodeName = node.nodeName;
-        if (nodeName === "#text")
-          continue;
+        if (nodeName === "#text") continue;
         if (nodeName === "comments") {
           props[nodeName] = parseComments(node.childNodes);
         } else {
@@ -71052,7 +77865,7 @@ ${content}</tr>
       var note = new osmNote(props);
       var item = encodeNoteRtree(note);
       _noteCache.note[note.id] = note;
-      _noteCache.rtree.insert(item);
+      updateRtree3(item, true);
       return note;
     },
     user: function parseUser2(obj, uid) {
@@ -71095,18 +77908,16 @@ ${content}</tr>
       _deferred.delete(handle);
       var results = [];
       var result;
-      for (var i2 = 0; i2 < children2.length; i2++) {
-        result = parseChild(children2[i2]);
-        if (result)
-          results.push(result);
+      for (var i3 = 0; i3 < children2.length; i3++) {
+        result = parseChild(children2[i3]);
+        if (result) results.push(result);
       }
       callback(null, results);
     });
     _deferred.add(handle);
     function parseChild(child) {
       var parser3 = parsers[child.nodeName];
-      if (!parser3)
-        return null;
+      if (!parser3) return null;
       var uid;
       if (child.nodeName === "user") {
         uid = child.attributes.id.value;
@@ -71119,17 +77930,16 @@ ${content}</tr>
       } else {
         uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
         if (options2.skipSeen) {
-          if (_tileCache.seen[uid])
-            return null;
+          if (_tileCache.seen[uid]) return null;
           _tileCache.seen[uid] = true;
         }
       }
       return parser3(child, uid);
     }
   }
-  function updateRtree4(item, replace) {
-    _noteCache.rtree.remove(item, function isEql(a, b) {
-      return a.data.id === b.data.id;
+  function updateRtree3(item, replace) {
+    _noteCache.rtree.remove(item, function isEql(a2, b2) {
+      return a2.data.id === b2.data.id;
     });
     if (replace) {
       _noteCache.rtree.insert(item);
@@ -71151,7 +77961,7 @@ ${content}</tr>
   }
   var osm_default = {
     init: function() {
-      utilRebind(this, dispatch7, "on");
+      utilRebind(this, dispatch9, "on");
     },
     reset: function() {
       Array.from(_deferred).forEach(function(handle) {
@@ -71162,13 +77972,12 @@ ${content}</tr>
       _userChangesets = void 0;
       _userDetails = void 0;
       _rateLimitError = void 0;
-      Object.values(_tileCache.inflight).forEach(abortRequest5);
-      Object.values(_noteCache.inflight).forEach(abortRequest5);
-      Object.values(_noteCache.inflightPost).forEach(abortRequest5);
-      if (_changeset.inflight)
-        abortRequest5(_changeset.inflight);
-      _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new import_rbush9.default() };
-      _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new import_rbush9.default() };
+      Object.values(_tileCache.inflight).forEach(abortRequest4);
+      Object.values(_noteCache.inflight).forEach(abortRequest4);
+      Object.values(_noteCache.inflightPost).forEach(abortRequest4);
+      if (_changeset.inflight) abortRequest4(_changeset.inflight);
+      _tileCache = { toLoad: {}, loaded: {}, inflight: {}, seen: {}, rtree: new RBush() };
+      _noteCache = { toLoad: {}, loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: new RBush() };
       _userCache = { toLoad: {}, user: {} };
       _cachedApiStatus = void 0;
       _changeset = {};
@@ -71180,12 +77989,15 @@ ${content}</tr>
     getUrlRoot: function() {
       return urlroot;
     },
+    getApiUrlRoot: function() {
+      return apiUrlroot;
+    },
     changesetURL: function(changesetID) {
       return urlroot + "/changeset/" + changesetID;
     },
     changesetsURL: function(center, zoom) {
-      var precision2 = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
-      return urlroot + "/history#map=" + Math.floor(zoom) + "/" + center[1].toFixed(precision2) + "/" + center[0].toFixed(precision2);
+      var precision3 = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
+      return urlroot + "/history#map=" + Math.floor(zoom) + "/" + center[1].toFixed(precision3) + "/" + center[0].toFixed(precision3);
     },
     entityURL: function(entity) {
       return urlroot + "/" + entity.type + "/" + entity.osmId();
@@ -71202,14 +78014,15 @@ ${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;
       var cid = _connectionID;
       function done(err, payload) {
         if (that.getConnectionId() !== cid) {
-          if (callback)
-            callback({ message: "Connection Switched", status: -1 });
+          if (callback) callback({ message: "Connection Switched", status: -1 });
           return;
         }
         var isAuthenticated = that.authenticated();
@@ -71219,7 +78032,7 @@ ${content}</tr>
         } else {
           if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
             _rateLimitError = err;
-            dispatch7.call("change");
+            dispatch9.call("change");
             that.reloadApiStatus();
           } else if (err && _cachedApiStatus === "online" || !err && _cachedApiStatus !== "online") {
             that.reloadApiStatus();
@@ -71238,9 +78051,12 @@ ${content}</tr>
         }
       }
       if (this.authenticated()) {
-        return oauth.xhr({ method: "GET", path }, done);
+        return oauth.xhr({
+          method: "GET",
+          path
+        }, done);
       } else {
-        var url = urlroot + path;
+        var url = apiUrlroot + path;
         var controller = new AbortController();
         var fn;
         if (path.indexOf(".json") !== -1) {
@@ -71251,8 +78067,7 @@ ${content}</tr>
         fn(url, { signal: controller.signal }).then(function(data) {
           done(null, data);
         }).catch(function(err) {
-          if (err.name === "AbortError")
-            return;
+          if (err.name === "AbortError") return;
           var match = err.message.match(/^\d{3}/);
           if (match) {
             done({ status: +match[0], statusText: err.message });
@@ -71263,66 +78078,90 @@ ${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 });
+          if (callback) callback(err, { data: entities });
         },
         options2
       );
     },
+    // Load a single note by id , XML format
+    // GET /api/0.6/notes/#id
+    loadEntityNote: function(id2, callback) {
+      var options2 = { skipSeen: false };
+      this.loadFromAPI(
+        "/api/0.6/notes/" + id2,
+        function(err, entities) {
+          if (callback) callback(err, { data: entities });
+        },
+        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 });
+          if (callback) callback(err, { data: entities });
         },
         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 });
+          if (callback) callback(err, { data: entities });
         },
         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 osmIDs = groups[k].map(function(id2) {
+      Object.keys(groups).forEach(function(k2) {
+        var type2 = k2 + "s";
+        var osmIDs = groups[k2].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 });
+              if (callback) callback(err, { data: entities });
             },
             options2
           );
         });
       });
     },
+    // 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) {
@@ -71361,8 +78200,7 @@ ${content}</tr>
       }
       function uploadedChangeset(err) {
         _changeset.inflight = null;
-        if (err)
-          return callback(err, changeset);
+        if (err) return callback(err, changeset);
         window.setTimeout(function() {
           callback(null, changeset);
         }, 2500);
@@ -71378,6 +78216,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 = [];
@@ -71391,66 +78232,65 @@ ${content}</tr>
       });
       if (cached.length || !this.authenticated()) {
         callback(void 0, cached);
-        if (!this.authenticated())
-          return;
-      }
-      utilArrayChunk(toLoad, 150).forEach(function(arr) {
-        oauth.xhr(
-          { method: "GET", path: "/api/0.6/users.json?users=" + arr.join() },
-          wrapcb(this, done, _connectionID)
-        );
-      }.bind(this));
+        if (!this.authenticated()) return;
+      }
+      utilArrayChunk(toLoad, 150).forEach((function(arr) {
+        oauth.xhr({
+          method: "GET",
+          path: "/api/0.6/users.json?users=" + arr.join()
+        }, wrapcb(this, done, _connectionID));
+      }).bind(this));
       function done(err, payload) {
-        if (err)
-          return callback(err);
+        if (err) return callback(err);
         var options2 = { skipSeen: true };
         return parseUserJSON(payload, function(err2, results) {
-          if (err2)
-            return callback(err2);
+          if (err2) return callback(err2);
           return callback(void 0, results);
         }, options2);
       }
     },
+    // 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];
         return callback(void 0, _userCache.user[uid]);
       }
-      oauth.xhr(
-        { method: "GET", path: "/api/0.6/user/" + uid + ".json" },
-        wrapcb(this, done, _connectionID)
-      );
+      oauth.xhr({
+        method: "GET",
+        path: "/api/0.6/user/" + uid + ".json"
+      }, wrapcb(this, done, _connectionID));
       function done(err, payload) {
-        if (err)
-          return callback(err);
+        if (err) return callback(err);
         var options2 = { skipSeen: true };
         return parseUserJSON(payload, function(err2, results) {
-          if (err2)
-            return callback(err2);
+          if (err2) return callback(err2);
           return callback(void 0, results[0]);
         }, options2);
       }
     },
+    // Load the details of the logged-in user
+    // GET /api/0.6/user/details
     userDetails: function(callback) {
       if (_userDetails) {
         return callback(void 0, _userDetails);
       }
-      oauth.xhr(
-        { method: "GET", path: "/api/0.6/user/details.json" },
-        wrapcb(this, done, _connectionID)
-      );
+      oauth.xhr({
+        method: "GET",
+        path: "/api/0.6/user/details.json"
+      }, wrapcb(this, done, _connectionID));
       function done(err, payload) {
-        if (err)
-          return callback(err);
+        if (err) return callback(err);
         var options2 = { skipSeen: false };
         return parseUserJSON(payload, function(err2, results) {
-          if (err2)
-            return callback(err2);
+          if (err2) return callback(err2);
           _userDetails = results[0];
           return callback(void 0, _userDetails);
         }, options2);
       }
     },
+    // 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);
@@ -71462,10 +78302,10 @@ ${content}</tr>
         if (err) {
           return callback(err);
         }
-        oauth.xhr(
-          { method: "GET", path: "/api/0.6/changesets?user=" + user.id },
-          wrapcb(this, done, _connectionID)
-        );
+        oauth.xhr({
+          method: "GET",
+          path: "/api/0.6/changesets?user=" + user.id
+        }, wrapcb(this, done, _connectionID));
       }
       function done(err, xml) {
         if (err) {
@@ -71483,8 +78323,10 @@ ${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 url = apiUrlroot + "/api/capabilities";
       var errback = wrapcb(this, done, _connectionID);
       xml_default(url).then(function(data) {
         errback(null, data);
@@ -71497,13 +78339,13 @@ ${content}</tr>
         }
         var elements = xml.getElementsByTagName("blacklist");
         var regexes = [];
-        for (var i2 = 0; i2 < elements.length; i2++) {
-          var regexString = elements[i2].getAttribute("regex");
+        for (var i3 = 0; i3 < elements.length; i3++) {
+          var regexString = elements[i3].getAttribute("regex");
           if (regexString) {
             try {
               var regex = new RegExp(regexString);
               regexes.push(regex);
-            } catch (e) {
+            } catch {
             }
           }
         }
@@ -71515,14 +78357,15 @@ ${content}</tr>
         } else {
           var waynodes = xml.getElementsByTagName("waynodes");
           var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute("maximum"), 10);
-          if (maxWayNodes && isFinite(maxWayNodes))
-            _maxWayNodes = maxWayNodes;
+          if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
           var apiStatus = xml.getElementsByTagName("status");
           var val = apiStatus[0].getAttribute("api");
           return callback(void 0, val);
         }
       }
     },
+    // Calls `status` and dispatches an `apiStatusChange` event if the returned
+    // status differs from the cached status.
     reloadApiStatus: function() {
       if (!this.throttledReloadApiStatus) {
         var that = this;
@@ -71530,36 +78373,38 @@ ${content}</tr>
           that.status(function(err, status) {
             if (status !== _cachedApiStatus) {
               _cachedApiStatus = status;
-              dispatch7.call("apiStatusChange", that, err, status);
+              dispatch9.call("apiStatusChange", that, err, status);
             }
           });
         }, 500);
       }
       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;
-      var tiles = tiler5.zoomExtent([_tileZoom4, _tileZoom4]).getTiles(projection2);
+      if (_off) return;
+      var tiles = tiler5.zoomExtent([_tileZoom3, _tileZoom3]).getTiles(projection2);
       var hadRequests = hasInflightRequests(_tileCache);
-      abortUnwantedRequests4(_tileCache, tiles);
+      abortUnwantedRequests3(_tileCache, tiles);
       if (hadRequests && !hasInflightRequests(_tileCache)) {
-        dispatch7.call("loaded");
+        dispatch9.call("loaded");
       }
       tiles.forEach(function(tile) {
         this.loadTile(tile, callback);
       }, this);
     },
+    // Load a single data tile
+    // GET /api/0.6/map?bbox=
     loadTile: function(tile, callback) {
-      if (_off)
-        return;
-      if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id])
-        return;
+      if (_off) return;
+      if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
       if (!hasInflightRequests(_tileCache)) {
-        dispatch7.call("loading");
+        dispatch9.call("loading");
       }
       var path = "/api/0.6/map.json?bbox=";
       var options2 = { skipSeen: true };
@@ -71573,54 +78418,52 @@ ${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));
         }
         if (!hasInflightRequests(_tileCache)) {
-          dispatch7.call("loaded");
+          dispatch9.call("loaded");
         }
       }
     },
     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;
-      var k = geoZoomToScale(_tileZoom4 + 1);
-      var offset = geoRawMercator().scale(k)(loc);
-      var projection2 = geoRawMercator().transform({ k, x: -offset[0], y: -offset[1] });
-      var tiles = tiler5.zoomExtent([_tileZoom4, _tileZoom4]).getTiles(projection2);
+      if (Object.keys(_tileCache.toLoad).length > 50) return;
+      var k2 = geoZoomToScale(_tileZoom3 + 1);
+      var offset = geoRawMercator().scale(k2)(loc);
+      var projection2 = geoRawMercator().transform({ k: k2, x: -offset[0], y: -offset[1] });
+      var tiles = tiler5.zoomExtent([_tileZoom3, _tileZoom3]).getTiles(projection2);
       tiles.forEach(function(tile) {
-        if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id])
-          return;
+        if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
         _tileCache.toLoad[tile.id] = true;
         this.loadTile(tile, callback);
       }, this);
     },
+    // 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)
-        return;
+      if (_off) return;
       var that = this;
       var path = "/api/0.6/notes?limit=" + noteOptions.limit + "&closed=" + noteOptions.closed + "&bbox=";
       var throttleLoadUsers = throttle_default(function() {
         var uids = Object.keys(_userCache.toLoad);
-        if (!uids.length)
-          return;
+        if (!uids.length) return;
         that.loadUsers(uids, function() {
         });
       }, 750);
       var tiles = tiler5.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection2);
-      abortUnwantedRequests4(_noteCache, tiles);
+      abortUnwantedRequests3(_noteCache, tiles);
       tiles.forEach(function(tile) {
-        if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id])
-          return;
+        if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
         var options2 = { skipSeen: false };
         _noteCache.inflight[tile.id] = that.loadFromAPI(
           path + tile.extent.toParam(),
@@ -71630,12 +78473,14 @@ ${content}</tr>
               _noteCache.loaded[tile.id] = true;
             }
             throttleLoadUsers();
-            dispatch7.call("loadedNotes");
+            dispatch9.call("loadedNotes");
           },
           options2
         );
       });
     },
+    // Create a note
+    // POST /api/0.6/notes?params
     postNoteCreate: function(note, callback) {
       if (!this.authenticated()) {
         return callback({ message: "Not Authenticated", status: -3 }, note);
@@ -71643,17 +78488,16 @@ ${content}</tr>
       if (_noteCache.inflightPost[note.id]) {
         return callback({ message: "Note update already inflight", status: -2 }, note);
       }
-      if (!note.loc[0] || !note.loc[1] || !note.newComment)
-        return;
+      if (!note.loc[0] || !note.loc[1] || !note.newComment) return;
       var comment = note.newComment;
       if (note.newCategory && note.newCategory !== "None") {
         comment += " #" + note.newCategory;
       }
       var path = "/api/0.6/notes?" + utilQsString({ lon: note.loc[0], lat: note.loc[1], text: comment });
-      _noteCache.inflightPost[note.id] = oauth.xhr(
-        { method: "POST", path },
-        wrapcb(this, done, _connectionID)
-      );
+      _noteCache.inflightPost[note.id] = oauth.xhr({
+        method: "POST",
+        path
+      }, wrapcb(this, done, _connectionID));
       function done(err, xml) {
         delete _noteCache.inflightPost[note.id];
         if (err) {
@@ -71670,6 +78514,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);
@@ -71684,17 +78532,16 @@ ${content}</tr>
         action = "reopen";
       } else {
         action = "comment";
-        if (!note.newComment)
-          return;
+        if (!note.newComment) return;
       }
       var path = "/api/0.6/notes/" + note.id + "/" + action;
       if (note.newComment) {
         path += "?" + utilQsString({ text: note.newComment });
       }
-      _noteCache.inflightPost[note.id] = oauth.xhr(
-        { method: "POST", path },
-        wrapcb(this, done, _connectionID)
-      );
+      _noteCache.inflightPost[note.id] = oauth.xhr({
+        method: "POST",
+        path
+      }, wrapcb(this, done, _connectionID));
       function done(err, xml) {
         delete _noteCache.inflightPost[note.id];
         if (err) {
@@ -71716,14 +78563,27 @@ ${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");
-      oauth.options(Object.assign(oldOptions, newOptions));
+      apiUrlroot = newOptions.apiUrl || urlroot;
+      if (newOptions.url && !newOptions.apiUrl) {
+        newOptions = {
+          ...newOptions,
+          apiUrl: newOptions.url
+        };
+      }
+      const oldOptions = utilObjectOmit(oauth.options(), "access_token");
+      oauth.options({ ...oldOptions, ...newOptions });
       this.reset();
       this.userChangesets(function() {
       });
-      dispatch7.call("change");
+      dispatch9.call("change");
       return this;
     },
     toggle: function(val) {
@@ -71733,19 +78593,22 @@ ${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 = {};
-        Object.keys(source).forEach(function(k) {
-          if (k === "rtree") {
-            target.rtree = new import_rbush9.default().fromJSON(source.rtree.toJSON());
-          } else if (k === "note") {
+        Object.keys(source).forEach(function(k2) {
+          if (k2 === "rtree") {
+            target.rtree = new RBush().fromJSON(source.rtree.toJSON());
+          } else if (k2 === "note") {
             target.note = {};
             Object.keys(source.note).forEach(function(id2) {
               target.note[id2] = osmNote(source.note[id2]);
             });
           } else {
-            target[k] = JSON.parse(JSON.stringify(source[k]));
+            target[k2] = JSON.parse(JSON.stringify(source[k2]));
           }
         });
         return target;
@@ -71782,7 +78645,7 @@ ${content}</tr>
       _userChangesets = void 0;
       _userDetails = void 0;
       oauth.logout();
-      dispatch7.call("change");
+      dispatch9.call("change");
       return this;
     },
     authenticated: function() {
@@ -71795,58 +78658,62 @@ ${content}</tr>
       _userDetails = void 0;
       function done(err, res) {
         if (err) {
-          if (callback)
-            callback(err);
+          if (callback) callback(err);
           return;
         }
         if (that.getConnectionId() !== cid) {
-          if (callback)
-            callback({ message: "Connection Switched", status: -1 });
+          if (callback) callback({ message: "Connection Switched", status: -1 });
           return;
         }
         _rateLimitError = void 0;
-        dispatch7.call("change");
-        if (callback)
-          callback(err, res);
+        dispatch9.call("change");
+        if (callback) callback(err, res);
         that.userChangesets(function() {
         });
       }
+      oauth.options({
+        ...oauth.options(),
+        locale: _mainLocalizer.localeCode()
+      });
       oauth.authenticate(done);
     },
     imageryBlocklists: function() {
       return _imageryBlocklists;
     },
     tileZoom: function(val) {
-      if (!arguments.length)
-        return _tileZoom4;
-      _tileZoom4 = val;
+      if (!arguments.length) return _tileZoom3;
+      _tileZoom3 = val;
       return this;
     },
+    // get all cached notes covering the viewport
     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) {
-        return d.data;
+      var bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+      return _noteCache.rtree.search(bbox2).map(function(d2) {
+        return d2.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;
+      if (!(note instanceof osmNote) || !note.id) return;
       delete _noteCache.note[note.id];
-      updateRtree4(encodeNoteRtree(note), false);
+      updateRtree3(encodeNoteRtree(note), false);
     },
+    // replace a single note in the cache
     replaceNote: function(note) {
-      if (!(note instanceof osmNote) || !note.id)
-        return;
+      if (!(note instanceof osmNote) || !note.id) return;
       _noteCache.note[note.id] = note;
-      updateRtree4(encodeNoteRtree(note), true);
+      updateRtree3(encodeNoteRtree(note), true);
       return note;
     },
+    // Get an array of note IDs closed during this session.
+    // Used to populate `closed:note` changeset tag
     getClosedIDs: function() {
       return Object.keys(_noteCache.closed).sort();
     }
@@ -71859,20 +78726,16 @@ ${content}</tr>
   var _localeIDs = { en: false };
   var debouncedRequest = debounce_default(request, 500, { leading: false });
   function request(url, callback) {
-    if (_inflight2[url])
-      return;
+    if (_inflight2[url]) return;
     var controller = new AbortController();
     _inflight2[url] = controller;
     json_default(url, { signal: controller.signal }).then(function(result) {
       delete _inflight2[url];
-      if (callback)
-        callback(null, result);
+      if (callback) callback(null, result);
     }).catch(function(err) {
       delete _inflight2[url];
-      if (err.name === "AbortError")
-        return;
-      if (callback)
-        callback(err.message);
+      if (err.name === "AbortError") return;
+      if (callback) callback(err.message);
     });
   }
   var osm_wikibase_default = {
@@ -71887,9 +78750,14 @@ ${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;
+      if (!entity.claims[property]) return void 0;
       var locale2 = _localeIDs[langCode];
       var preferredPick, localePick;
       entity.claims[property].forEach(function(stmt) {
@@ -71908,9 +78776,13 @@ ${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;
+      if (!entity || !entity.claims[property]) return void 0;
       return entity.claims[property].reduce(function(acc, obj) {
         var value = obj.mainsnak.datavalue.value;
         acc[value.language] = value.text;
@@ -71921,6 +78793,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,18 +78850,21 @@ ${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) {
+      doRequest(url, function(err, d2) {
         if (err) {
           callback(err);
-        } else if (!d.success || d.error) {
-          callback(d.error.messages.map(function(v) {
-            return v.html["*"];
+        } else if (!d2.success || d2.error) {
+          callback(d2.error.messages.map(function(v2) {
+            return v2.html["*"];
           }).join("<br>"));
         } else {
           var localeID = false;
-          Object.values(d.entities).forEach(function(res) {
+          Object.values(d2.entities).forEach(function(res) {
             if (res.missing !== "") {
               var title = res.sitelinks.wiki.title;
               if (title === rtypeSitelink) {
@@ -72007,6 +78890,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) {
@@ -72023,17 +78922,16 @@ ${content}</tr>
           callback("No entity");
           return;
         }
-        var i2;
+        var i3;
         var description;
-        for (i2 in langCodes) {
-          let code2 = langCodes[i2];
+        for (i3 in langCodes) {
+          let code2 = langCodes[i3];
           if (entity.descriptions[code2] && entity.descriptions[code2].language === code2) {
             description = entity.descriptions[code2];
             break;
           }
         }
-        if (!description && Object.values(entity.descriptions).length)
-          description = Object.values(entity.descriptions)[0];
+        if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0];
         var result = {
           title: entity.title,
           description: description ? description.value : "",
@@ -72062,8 +78960,8 @@ ${content}</tr>
         var tagWiki = that.monolingualClaimToValueObj(data.tag, "P31");
         var keyWiki = that.monolingualClaimToValueObj(data.key, "P31");
         var wikis = [rtypeWiki, tagWiki, keyWiki];
-        for (i2 in wikis) {
-          var wiki = wikis[i2];
+        for (i3 in wikis) {
+          var wiki = wikis[i3];
           for (var j2 in langCodes) {
             var code = langCodes[j2];
             var referenceId = langCodes[0].split("-")[0] !== "en" && code.split("-")[0] === "en" ? "inspector.wiki_en_reference" : "inspector.wiki_reference";
@@ -72073,8 +78971,7 @@ ${content}</tr>
               break;
             }
           }
-          if (result.wiki)
-            break;
+          if (result.wiki) break;
         }
         callback(null, result);
         function getWikiInfo(wiki2, langCode, tKey) {
@@ -72092,76 +78989,21 @@ ${content}</tr>
       _localeIDs[langCode] = qid;
     },
     apibase: function(val) {
-      if (!arguments.length)
-        return apibase3;
+      if (!arguments.length) return apibase3;
       apibase3 = val;
       return this;
     }
   };
 
   // modules/services/streetside.js
-  var import_rbush10 = __toESM(require_rbush_min());
-
-  // modules/util/jsonp_request.js
-  var jsonpCache = {};
-  window.jsonpCache = jsonpCache;
-  function jsonpRequest(url, callback) {
-    var request3 = {
-      abort: function() {
-      }
-    };
-    if (window.JSONP_FIX) {
-      if (window.JSONP_DELAY === 0) {
-        callback(window.JSONP_FIX);
-      } else {
-        var t = window.setTimeout(function() {
-          callback(window.JSONP_FIX);
-        }, window.JSONP_DELAY || 0);
-        request3.abort = function() {
-          window.clearTimeout(t);
-        };
-      }
-      return request3;
-    }
-    function rand() {
-      var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-      var c = "";
-      var i2 = -1;
-      while (++i2 < 15)
-        c += chars.charAt(Math.floor(Math.random() * 52));
-      return c;
-    }
-    function create2(url2) {
-      var e = url2.match(/callback=(\w+)/);
-      var c = e ? e[1] : rand();
-      jsonpCache[c] = function(data) {
-        if (jsonpCache[c]) {
-          callback(data);
-        }
-        finalize();
-      };
-      function finalize() {
-        delete jsonpCache[c];
-        script.remove();
-      }
-      request3.abort = finalize;
-      return "jsonpCache." + c;
-    }
-    var cb = create2(url);
-    var script = select_default2("head").append("script").attr("type", "text/javascript").attr("src", url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
-    return request3;
-  }
-
-  // modules/services/streetside.js
-  var bubbleApi = "https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?";
-  var streetsideImagesApi = "https://t.ssl.ak.tiles.virtualearth.net/tiles/";
-  var bubbleAppKey = "AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm";
-  var pannellumViewerCSS = "pannellum-streetside/pannellum.css";
-  var pannellumViewerJS = "pannellum-streetside/pannellum.js";
-  var maxResults2 = 2e3;
-  var tileZoom2 = 16.5;
-  var tiler6 = utilTiler().zoomExtent([tileZoom2, tileZoom2]).skipNullIsland(true);
-  var dispatch8 = dispatch_default("loadedImages", "viewerChanged");
+  var streetsideApi = "https://dev.virtualearth.net/REST/v1/Imagery/MetaData/Streetside?mapArea={bbox}&key={key}&count={count}";
+  var maxResults2 = 500;
+  var bubbleAppKey = utilAesDecrypt("5c875730b09c6b422433e807e1ff060b6536c791dbfffcffc4c6b18a1bdba1f14593d151adb50e19e1be1ab19aef813bf135d0f103475e5c724dec94389e45d0");
+  var pannellumViewerCSS2 = "pannellum/pannellum.css";
+  var pannellumViewerJS2 = "pannellum/pannellum.js";
+  var tileZoom3 = 16.5;
+  var tiler6 = utilTiler().zoomExtent([tileZoom3, tileZoom3]).skipNullIsland(true);
+  var dispatch10 = dispatch_default("loadedImages", "viewerChanged");
   var minHfov = 10;
   var maxHfov = 90;
   var defaultHfov = 45;
@@ -72169,7 +79011,7 @@ ${content}</tr>
   var _resolution = 512;
   var _currScene = 0;
   var _ssCache;
-  var _pannellumViewer;
+  var _pannellumViewer2;
   var _sceneOptions = {
     showFullscreenCtrl: false,
     autoLoad: true,
@@ -72181,27 +79023,25 @@ ${content}</tr>
     type: "cubemap",
     cubeMap: []
   };
-  var _loadViewerPromise3;
-  function abortRequest6(i2) {
-    i2.abort();
+  var _loadViewerPromise4;
+  function abortRequest5(i3) {
+    i3.abort();
   }
-  function localeTimestamp(s) {
-    if (!s)
-      return null;
+  function localeTimestamp2(s2) {
+    if (!s2) return null;
     const options2 = { day: "numeric", month: "short", year: "numeric" };
-    const d = new Date(s);
-    if (isNaN(d.getTime()))
-      return null;
-    return d.toLocaleString(_mainLocalizer.localeCode(), options2);
+    const d2 = new Date(s2);
+    if (isNaN(d2.getTime())) return null;
+    return d2.toLocaleString(_mainLocalizer.localeCode(), options2);
   }
   function loadTiles3(which, url, projection2, margin) {
     const tiles = tiler6.margin(margin).getTiles(projection2);
     const cache = _ssCache[which];
-    Object.keys(cache.inflight).forEach((k) => {
-      const wanted = tiles.find((tile) => k.indexOf(tile.id + ",") === 0);
+    Object.keys(cache.inflight).forEach((k2) => {
+      const wanted = tiles.find((tile) => k2.indexOf(tile.id + ",") === 0);
       if (!wanted) {
-        abortRequest6(cache.inflight[k]);
-        delete cache.inflight[k];
+        abortRequest5(cache.inflight[k2]);
+        delete cache.inflight[k2];
       }
     });
     tiles.forEach((tile) => loadNextTilePage2(which, url, tile));
@@ -72210,118 +79050,89 @@ ${content}</tr>
     const cache = _ssCache[which];
     const nextPage = cache.nextPage[tile.id] || 0;
     const id2 = tile.id + "," + String(nextPage);
-    if (cache.loaded[id2] || cache.inflight[id2])
-      return;
-    cache.inflight[id2] = getBubbles(url, tile, (bubbles) => {
+    if (cache.loaded[id2] || cache.inflight[id2]) return;
+    cache.inflight[id2] = getBubbles(url, tile, (response) => {
       cache.loaded[id2] = true;
       delete cache.inflight[id2];
-      if (!bubbles)
-        return;
-      bubbles.shift();
-      const features2 = bubbles.map((bubble) => {
-        if (cache.points[bubble.id])
-          return null;
-        const loc = [bubble.lo, bubble.la];
-        const d = {
+      if (!response) return;
+      if (response.resourceSets[0].resources.length === maxResults2) {
+        const split = tile.extent.split();
+        loadNextTilePage2(which, url, { id: tile.id + ",a", extent: split[0] });
+        loadNextTilePage2(which, url, { id: tile.id + ",b", extent: split[1] });
+        loadNextTilePage2(which, url, { id: tile.id + ",c", extent: split[2] });
+        loadNextTilePage2(which, url, { id: tile.id + ",d", extent: split[3] });
+      }
+      const features = response.resourceSets[0].resources.map((bubble) => {
+        const bubbleId = bubble.imageUrl;
+        if (cache.points[bubbleId]) return null;
+        const loc = [
+          bubble.lon || bubble.longitude,
+          bubble.lat || bubble.latitude
+        ];
+        const d2 = {
           loc,
-          key: bubble.id,
-          ca: bubble.he,
-          captured_at: bubble.cd,
+          key: bubbleId,
+          imageUrl: bubble.imageUrl.replace(
+            "{subdomain}",
+            bubble.imageUrlSubdomains[0]
+          ),
+          ca: bubble.he || bubble.heading,
+          captured_at: bubble.vintageEnd,
           captured_by: "microsoft",
-          pr: bubble.pr,
-          ne: bubble.ne,
           pano: true,
           sequenceKey: null
         };
-        cache.points[bubble.id] = d;
-        if (bubble.pr === void 0) {
-          cache.leaders.push(bubble.id);
-        }
+        cache.points[bubbleId] = d2;
         return {
           minX: loc[0],
           minY: loc[1],
           maxX: loc[0],
           maxY: loc[1],
-          data: d
+          data: d2
         };
       }).filter(Boolean);
-      cache.rtree.load(features2);
-      connectSequences();
+      cache.rtree.load(features);
       if (which === "bubbles") {
-        dispatch8.call("loadedImages");
+        dispatch10.call("loadedImages");
       }
     });
   }
-  function connectSequences() {
-    let cache = _ssCache.bubbles;
-    let keepLeaders = [];
-    for (let i2 = 0; i2 < cache.leaders.length; i2++) {
-      let bubble = cache.points[cache.leaders[i2]];
-      let seen = {};
-      let sequence = { key: bubble.key, bubbles: [] };
-      let complete = false;
-      do {
-        sequence.bubbles.push(bubble);
-        seen[bubble.key] = true;
-        if (bubble.ne === void 0) {
-          complete = true;
-        } else {
-          bubble = cache.points[bubble.ne];
-        }
-      } while (bubble && !seen[bubble.key] && !complete);
-      if (complete) {
-        _ssCache.sequences[sequence.key] = sequence;
-        for (let j2 = 0; j2 < sequence.bubbles.length; j2++) {
-          sequence.bubbles[j2].sequenceKey = sequence.key;
-        }
-        sequence.geojson = {
-          type: "LineString",
-          properties: {
-            captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
-            captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
-            key: sequence.key
-          },
-          coordinates: sequence.bubbles.map((d) => d.loc)
-        };
-      } else {
-        keepLeaders.push(cache.leaders[i2]);
-      }
-    }
-    cache.leaders = keepLeaders;
-  }
   function getBubbles(url, tile, callback) {
     let rect = tile.extent.rectangle();
-    let urlForRequest = url + utilQsString({
-      n: rect[3],
-      s: rect[1],
-      e: rect[2],
-      w: rect[0],
-      c: maxResults2,
-      appkey: bubbleAppKey,
-      jsCallback: "{callback}"
-    });
-    return jsonpRequest(urlForRequest, (data) => {
-      if (!data || data.error) {
+    let urlForRequest = url.replace("{key}", bubbleAppKey).replace("{bbox}", [rect[1], rect[0], rect[3], rect[2]].join(",")).replace("{count}", maxResults2);
+    const controller = new AbortController();
+    fetch(urlForRequest, { signal: controller.signal }).then(function(response) {
+      if (!response.ok) {
+        throw new Error(response.status + " " + response.statusText);
+      }
+      return response.json();
+    }).then(function(result) {
+      if (!result) {
         callback(null);
+      }
+      return callback(result || []);
+    }).catch(function(err) {
+      if (err.name === "AbortError") {
       } else {
-        callback(data);
+        throw new Error(err);
       }
     });
+    return controller;
   }
-  function partitionViewport3(projection2) {
-    let z = geoScaleToZoom(projection2.scale());
-    let z2 = Math.ceil(z * 2) / 2 + 2.5;
-    let tiler8 = utilTiler().zoomExtent([z2, z2]);
+  function partitionViewport4(projection2) {
+    let z2 = geoScaleToZoom(projection2.scale());
+    let z22 = Math.ceil(z2 * 2) / 2 + 2.5;
+    let tiler8 = utilTiler().zoomExtent([z22, z22]);
     return tiler8.getTiles(projection2).map((tile) => tile.extent);
   }
-  function searchLimited3(limit, projection2, rtree) {
+  function searchLimited4(limit, projection2, rtree) {
     limit = limit || 5;
-    return partitionViewport3(projection2).reduce((result, extent) => {
-      let found = rtree.search(extent.bbox()).slice(0, limit).map((d) => d.data);
+    return partitionViewport4(projection2).reduce((result, extent) => {
+      let found = rtree.search(extent.bbox()).slice(0, limit).map((d2) => d2.data);
       return found.length ? result.concat(found) : result;
     }, []);
   }
-  function loadImage(imgInfo) {
+  function loadImage2(imgInfo) {
     return new Promise((resolve) => {
       let img = new Image();
       img.onload = () => {
@@ -72338,7 +79149,7 @@ ${content}</tr>
     });
   }
   function loadCanvas(imageGroup) {
-    return Promise.all(imageGroup.map(loadImage)).then((data) => {
+    return Promise.all(imageGroup.map(loadImage2)).then((data) => {
       let canvas = document.getElementById("ideditor-canvas" + data[0].imgInfo.face);
       const which = { "01": 0, "02": 1, "03": 2, "10": 3, "11": 4, "12": 5 };
       let face = data[0].imgInfo.face;
@@ -72355,19 +79166,19 @@ ${content}</tr>
     if (reset) {
       selection2.selectAll("#ideditor-stitcher-canvases").remove();
     }
-    selection2.selectAll("#ideditor-stitcher-canvases").data([0]).enter().append("div").attr("id", "ideditor-stitcher-canvases").attr("display", "none").selectAll("canvas").data(["canvas01", "canvas02", "canvas03", "canvas10", "canvas11", "canvas12"]).enter().append("canvas").attr("id", (d) => "ideditor-" + d).attr("width", _resolution).attr("height", _resolution);
+    selection2.selectAll("#ideditor-stitcher-canvases").data([0]).enter().append("div").attr("id", "ideditor-stitcher-canvases").attr("display", "none").selectAll("canvas").data(["canvas01", "canvas02", "canvas03", "canvas10", "canvas11", "canvas12"]).enter().append("canvas").attr("id", (d2) => "ideditor-" + d2).attr("width", _resolution).attr("height", _resolution);
   }
   function qkToXY(qk) {
-    let x = 0;
-    let y = 0;
+    let x2 = 0;
+    let y2 = 0;
     let scale = 256;
-    for (let i2 = qk.length; i2 > 0; i2--) {
-      const key = qk[i2 - 1];
-      x += +(key === "1" || key === "3") * scale;
-      y += +(key === "2" || key === "3") * scale;
+    for (let i3 = qk.length; i3 > 0; i3--) {
+      const key = qk[i3 - 1];
+      x2 += +(key === "1" || key === "3") * scale;
+      y2 += +(key === "2" || key === "3") * scale;
       scale *= 2;
     }
-    return [x, y];
+    return [x2, y2];
   }
   function getQuadKeys() {
     let dim = _resolution / 256;
@@ -72728,24 +79539,33 @@ ${content}</tr>
     return quadKeys;
   }
   var streetside_default = {
+    /**
+     * init() initialize streetside.
+     */
     init: function() {
       if (!_ssCache) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch8, "on");
+      this.event = utilRebind(this, dispatch10, "on");
     },
+    /**
+     * reset() reset the cache.
+     */
     reset: function() {
       if (_ssCache) {
-        Object.values(_ssCache.bubbles.inflight).forEach(abortRequest6);
+        Object.values(_ssCache.bubbles.inflight).forEach(abortRequest5);
       }
       _ssCache = {
-        bubbles: { inflight: {}, loaded: {}, nextPage: {}, rtree: new import_rbush10.default(), points: {}, leaders: [] },
+        bubbles: { inflight: {}, loaded: {}, nextPage: {}, rtree: new RBush(), points: {} },
         sequences: {}
       };
     },
+    /**
+     * bubbles()
+     */
     bubbles: function(projection2) {
       const limit = 5;
-      return searchLimited3(limit, projection2, _ssCache.bubbles.rtree);
+      return searchLimited4(limit, projection2, _ssCache.bubbles.rtree);
     },
     cachedImage: function(imageKey) {
       return _ssCache.bubbles.points[imageKey];
@@ -72754,11 +79574,11 @@ ${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) => {
-        const key = d.data.sequenceKey;
+      _ssCache.bubbles.rtree.search(bbox2).forEach((d2) => {
+        const key = d2.data.sequenceKey;
         if (key && !seen[key]) {
           seen[key] = true;
           results.push(_ssCache.sequences[key].geojson);
@@ -72766,19 +79586,19 @@ ${content}</tr>
       });
       return results;
     },
+    /**
+     * loadBubbles()
+     */
     loadBubbles: function(projection2, margin) {
-      if (margin === void 0)
-        margin = 2;
-      loadTiles3("bubbles", bubbleApi, projection2, margin);
+      if (margin === void 0) margin = 2;
+      loadTiles3("bubbles", streetsideApi, projection2, margin);
     },
     viewer: function() {
-      return _pannellumViewer;
+      return _pannellumViewer2;
     },
     initViewer: function() {
-      if (!window.pannellum)
-        return;
-      if (_pannellumViewer)
-        return;
+      if (!window.pannellum) return;
+      if (_pannellumViewer2) return;
       _currScene += 1;
       const sceneID = _currScene.toString();
       const options2 = {
@@ -72786,25 +79606,24 @@ ${content}</tr>
         scenes: {}
       };
       options2.scenes[sceneID] = _sceneOptions;
-      _pannellumViewer = window.pannellum.viewer("ideditor-viewer-streetside", options2);
+      _pannellumViewer2 = window.pannellum.viewer("ideditor-viewer-streetside", options2);
     },
     ensureViewerLoaded: function(context) {
-      if (_loadViewerPromise3)
-        return _loadViewerPromise3;
+      if (_loadViewerPromise4) return _loadViewerPromise4;
       let wrap2 = context.container().select(".photoviewer").selectAll(".ms-wrapper").data([0]);
       let wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper ms-wrapper").classed("hide", true);
       let that = this;
       let pointerPrefix = "PointerEvent" in window ? "pointer" : "mouse";
       wrapEnter.append("div").attr("id", "ideditor-viewer-streetside").on(pointerPrefix + "down.streetside", () => {
         select_default2(window).on(pointerPrefix + "move.streetside", () => {
-          dispatch8.call("viewerChanged");
+          dispatch10.call("viewerChanged");
         }, true);
       }).on(pointerPrefix + "up.streetside pointercancel.streetside", () => {
         select_default2(window).on(pointerPrefix + "move.streetside", null);
-        let t = timer((elapsed) => {
-          dispatch8.call("viewerChanged");
+        let t2 = timer((elapsed) => {
+          dispatch10.call("viewerChanged");
           if (elapsed > 2e3) {
-            t.stop();
+            t2.stop();
           }
         });
       }).append("div").attr("class", "photo-attribution fillD");
@@ -72813,36 +79632,34 @@ ${content}</tr>
       controlsEnter.append("button").on("click.forward", step(1)).text("\u25BA");
       wrap2 = wrap2.merge(wrapEnter).call(setupCanvas, true);
       context.ui().photoviewer.on("resize.streetside", () => {
-        if (_pannellumViewer) {
-          _pannellumViewer.resize();
+        if (_pannellumViewer2) {
+          _pannellumViewer2.resize();
         }
       });
-      _loadViewerPromise3 = new Promise((resolve, reject) => {
+      _loadViewerPromise4 = new Promise((resolve, reject) => {
         let loadedCount = 0;
         function loaded() {
           loadedCount += 1;
-          if (loadedCount === 2)
-            resolve();
+          if (loadedCount === 2) resolve();
         }
         const head = select_default2("head");
-        head.selectAll("#ideditor-streetside-viewercss").data([0]).enter().append("link").attr("id", "ideditor-streetside-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(pannellumViewerCSS)).on("load.serviceStreetside", loaded).on("error.serviceStreetside", function() {
+        head.selectAll("#ideditor-streetside-viewercss").data([0]).enter().append("link").attr("id", "ideditor-streetside-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(pannellumViewerCSS2)).on("load.serviceStreetside", loaded).on("error.serviceStreetside", function() {
           reject();
         });
-        head.selectAll("#ideditor-streetside-viewerjs").data([0]).enter().append("script").attr("id", "ideditor-streetside-viewerjs").attr("crossorigin", "anonymous").attr("src", context.asset(pannellumViewerJS)).on("load.serviceStreetside", loaded).on("error.serviceStreetside", function() {
+        head.selectAll("#ideditor-streetside-viewerjs").data([0]).enter().append("script").attr("id", "ideditor-streetside-viewerjs").attr("crossorigin", "anonymous").attr("src", context.asset(pannellumViewerJS2)).on("load.serviceStreetside", loaded).on("error.serviceStreetside", function() {
           reject();
         });
       }).catch(function() {
-        _loadViewerPromise3 = null;
+        _loadViewerPromise4 = null;
       });
-      return _loadViewerPromise3;
+      return _loadViewerPromise4;
       function step(stepBy) {
         return () => {
           let viewer = context.container().select(".photoviewer");
           let selected = viewer.empty() ? void 0 : viewer.datum();
-          if (!selected)
-            return;
+          if (!selected) return;
           let nextID = stepBy === 1 ? selected.ne : selected.pr;
-          let yaw = _pannellumViewer.getYaw();
+          let yaw = _pannellumViewer2.getYaw();
           let ca = selected.ca + yaw;
           let origin = selected.loc;
           const meters = 35;
@@ -72869,36 +79686,35 @@ ${content}</tr>
             return extent2.extend(geoExtent(point));
           }, geoExtent());
           let minDist = Infinity;
-          _ssCache.bubbles.rtree.search(extent.bbox()).forEach((d) => {
-            if (d.data.key === selected.key)
-              return;
-            if (!geoPointInPolygon(d.data.loc, poly))
-              return;
-            let dist = geoVecLength(d.data.loc, selected.loc);
-            let theta = selected.ca - d.data.ca;
+          _ssCache.bubbles.rtree.search(extent.bbox()).forEach((d2) => {
+            if (d2.data.key === selected.key) return;
+            if (!geoPointInPolygon(d2.data.loc, poly)) return;
+            let dist = geoVecLength(d2.data.loc, selected.loc);
+            let theta = selected.ca - d2.data.ca;
             let minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
             if (minTheta > 20) {
               dist += 5;
             }
             if (dist < minDist) {
-              nextID = d.data.key;
+              nextID = d2.data.key;
               minDist = dist;
             }
           });
           let nextBubble = nextID && that.cachedImage(nextID);
-          if (!nextBubble)
-            return;
+          if (!nextBubble) return;
           context.map().centerEase(nextBubble.loc);
           that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
         };
       }
     },
     yaw: function(yaw) {
-      if (typeof yaw !== "number")
-        return yaw;
+      if (typeof yaw !== "number") return yaw;
       _sceneOptions.yaw = yaw;
       return this;
     },
+    /**
+     * showViewer()
+     */
     showViewer: function(context) {
       let wrap2 = context.container().select(".photoviewer").classed("hide", false);
       let isHidden = wrap2.selectAll(".photo-wrapper.ms-wrapper.hide").size();
@@ -72908,29 +79724,32 @@ ${content}</tr>
       }
       return this;
     },
+    /**
+     * hideViewer()
+     */
     hideViewer: function(context) {
       let viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(null);
+      if (!viewer.empty()) viewer.datum(null);
       viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
       context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
       this.updateUrlImage(null);
       return this.setStyles(context, null, true);
     },
+    /**
+     * selectImage().
+     */
     selectImage: function(context, key) {
       let that = this;
-      let d = this.cachedImage(key);
+      let d2 = this.cachedImage(key);
       let viewer = context.container().select(".photoviewer");
-      if (!viewer.empty())
-        viewer.datum(d);
+      if (!viewer.empty()) viewer.datum(d2);
       this.setStyles(context, null, true);
       let wrap2 = context.container().select(".photoviewer .ms-wrapper");
       let attribution = wrap2.selectAll(".photo-attribution").html("");
       wrap2.selectAll(".pnlm-load-box").style("display", "block");
-      if (!d)
-        return this;
+      if (!d2) return this;
       this.updateUrlImage(key);
-      _sceneOptions.northOffset = d.ca;
+      _sceneOptions.northOffset = d2.ca;
       let line1 = attribution.append("div").attr("class", "attribution-row");
       const hiresDomId = utilUniqueDomId("streetside-hires");
       let label = line1.append("label").attr("for", hiresDomId).attr("class", "streetside-hires");
@@ -72940,33 +79759,26 @@ ${content}</tr>
         _resolution = _hires ? 1024 : 512;
         wrap2.call(setupCanvas, true);
         let viewstate = {
-          yaw: _pannellumViewer.getYaw(),
-          pitch: _pannellumViewer.getPitch(),
-          hfov: _pannellumViewer.getHfov()
+          yaw: _pannellumViewer2.getYaw(),
+          pitch: _pannellumViewer2.getPitch(),
+          hfov: _pannellumViewer2.getHfov()
         };
         _sceneOptions = Object.assign(_sceneOptions, viewstate);
-        that.selectImage(context, d.key).showViewer(context);
+        that.selectImage(context, d2.key).showViewer(context);
       });
       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();
+      if (d2.captured_by) {
+        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("|");
       }
-      if (d.captured_at) {
-        captureInfo.append("span").attr("class", "captured_at").text(localeTimestamp(d.captured_at));
+      if (d2.captured_at) {
+        captureInfo.append("span").attr("class", "captured_at").text(localeTimestamp2(d2.captured_at));
       }
       let line2 = attribution.append("div").attr("class", "attribution-row");
-      line2.append("a").attr("class", "image-view-link").attr("target", "_blank").attr("href", "https://www.bing.com/maps?cp=" + d.loc[1] + "~" + d.loc[0] + "&lvl=17&dir=" + d.ca + "&style=x&v=2&sV=1").call(_t.append("streetside.view_on_bing"));
-      line2.append("a").attr("class", "image-report-link").attr("target", "_blank").attr("href", "https://www.bing.com/maps/privacyreport/streetsideprivacyreport?bubbleid=" + encodeURIComponent(d.key) + "&focus=photo&lat=" + d.loc[1] + "&lng=" + d.loc[0] + "&z=17").call(_t.append("streetside.report"));
-      let bubbleIdQuadKey = d.key.toString(4);
-      const paddingNeeded = 16 - bubbleIdQuadKey.length;
-      for (let i2 = 0; i2 < paddingNeeded; i2++) {
-        bubbleIdQuadKey = "0" + bubbleIdQuadKey;
-      }
-      const imgUrlPrefix = streetsideImagesApi + "hs" + bubbleIdQuadKey;
-      const imgUrlSuffix = ".jpg?g=6338&n=z";
+      line2.append("a").attr("class", "image-view-link").attr("target", "_blank").attr("href", "https://www.bing.com/maps?cp=" + d2.loc[1] + "~" + d2.loc[0] + "&lvl=17&dir=" + d2.ca + "&style=x&v=2&sV=1").call(_t.append("streetside.view_on_bing"));
+      line2.append("a").attr("class", "image-report-link").attr("target", "_blank").attr("href", "https://www.bing.com/maps/privacyreport/streetsideprivacyreport?bubbleid=" + encodeURIComponent(d2.key) + "&focus=photo&lat=" + d2.loc[1] + "&lng=" + d2.loc[0] + "&z=17").call(_t.append("streetside.report"));
       const faceKeys = ["01", "02", "03", "10", "11", "12"];
       let quadKeys = getQuadKeys();
       let faces = faceKeys.map((faceKey) => {
@@ -72974,30 +79786,33 @@ ${content}</tr>
           const xy = qkToXY(quadKey);
           return {
             face: faceKey,
-            url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
+            url: d2.imageUrl.replace("{faceId}", faceKey).replace("{tileId}", quadKey),
             x: xy[0],
             y: xy[1]
           };
         });
       });
       loadFaces(faces).then(function() {
-        if (!_pannellumViewer) {
+        if (!_pannellumViewer2) {
           that.initViewer();
         } else {
           _currScene += 1;
           let sceneID = _currScene.toString();
-          _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID);
+          _pannellumViewer2.addScene(sceneID, _sceneOptions).loadScene(sceneID);
           if (_currScene > 2) {
             sceneID = (_currScene - 1).toString();
-            _pannellumViewer.removeScene(sceneID);
+            _pannellumViewer2.removeScene(sceneID);
           }
         }
       });
       return this;
     },
-    getSequenceKeyForBubble: function(d) {
-      return d && d.sequenceKey;
+    getSequenceKeyForBubble: function(d2) {
+      return d2 && d2.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);
@@ -73006,20 +79821,20 @@ ${content}</tr>
       let hoveredBubbleKey = hovered && hovered.key;
       let hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
       let hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
-      let hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map((d) => d.key) || [];
+      let hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map((d2) => d2.key) || [];
       let viewer = context.container().select(".photoviewer");
       let selected = viewer.empty() ? void 0 : viewer.datum();
       let selectedBubbleKey = selected && selected.key;
       let selectedSequenceKey = this.getSequenceKeyForBubble(selected);
       let selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
-      let selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map((d) => d.key) || [];
+      let selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map((d2) => d2.key) || [];
       let highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
-      context.container().selectAll(".layer-streetside-images .viewfield-group").classed("highlighted", (d) => highlightedBubbleKeys.indexOf(d.key) !== -1).classed("hovered", (d) => d.key === hoveredBubbleKey).classed("currentView", (d) => d.key === selectedBubbleKey);
-      context.container().selectAll(".layer-streetside-images .sequence").classed("highlighted", (d) => d.properties.key === hoveredSequenceKey).classed("currentView", (d) => d.properties.key === selectedSequenceKey);
+      context.container().selectAll(".layer-streetside-images .viewfield-group").classed("highlighted", (d2) => highlightedBubbleKeys.indexOf(d2.key) !== -1).classed("hovered", (d2) => d2.key === hoveredBubbleKey).classed("currentView", (d2) => d2.key === selectedBubbleKey);
+      context.container().selectAll(".layer-streetside-images .sequence").classed("highlighted", (d2) => d2.properties.key === hoveredSequenceKey).classed("currentView", (d2) => d2.properties.key === selectedSequenceKey);
       context.container().selectAll(".layer-streetside-images .viewfield-group .viewfield").attr("d", viewfieldPath);
       function viewfieldPath() {
-        let d = this.parentNode.__data__;
-        if (d.pano && d.key !== selectedBubbleKey) {
+        let d2 = this.parentNode.__data__;
+        if (d2.pano && d2.key !== selectedBubbleKey) {
           return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
         } else {
           return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
@@ -73038,13 +79853,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 = {};
@@ -73074,9 +79892,9 @@ ${content}</tr>
     line: "count_way_members_fraction",
     relation: "count_relation_members_fraction"
   };
-  function sets(params, n2, o) {
-    if (params.geometry && o[params.geometry]) {
-      params[n2] = o[params.geometry];
+  function sets(params, n3, o2) {
+    if (params.geometry && o2[params.geometry]) {
+      params[n3] = o2[params.geometry];
     }
     return params;
   }
@@ -73092,77 +79910,68 @@ ${content}</tr>
   function clean(params) {
     return utilObjectOmit(params, ["geometry", "debounce"]);
   }
-  function filterKeys(type3) {
-    var count_type = type3 ? "count_" + type3 : "count_all";
-    return function(d) {
-      return parseFloat(d[count_type]) > 2500 || d.in_wiki;
+  function filterKeys(type2) {
+    var count_type = type2 ? "count_" + type2 : "count_all";
+    return function(d2) {
+      return Number(d2[count_type]) > 2500 || d2.in_wiki;
     };
   }
   function filterMultikeys(prefix) {
-    return function(d) {
-      var re2 = new RegExp("^" + prefix + "(.*)$");
-      var matches = d.key.match(re2) || [];
+    return function(d2) {
+      var re3 = new RegExp("^" + prefix + "(.*)$", "i");
+      var matches = d2.key.match(re3) || [];
       return matches.length === 2 && matches[1].indexOf(":") === -1;
     };
   }
   function filterValues(allowUpperCase) {
-    return function(d) {
-      if (d.value.match(/[;,]/) !== null)
-        return false;
-      if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null)
-        return false;
-      return d.count > 100 || d.in_wiki;
+    return function(d2) {
+      if (d2.value.match(/[;,]/) !== null) return false;
+      if (!allowUpperCase && d2.value.match(/[A-Z*]/) !== null) return false;
+      return d2.count > 100 || d2.in_wiki;
     };
   }
   function filterRoles(geometry) {
-    return function(d) {
-      if (d.role === "")
-        return false;
-      if (d.role.match(/[A-Z*;,]/) !== null)
-        return false;
-      return parseFloat(d[tag_members_fractions[geometry]]) > 0;
+    return function(d2) {
+      if (d2.role === "") return false;
+      if (d2.role.match(/[A-Z*;,]/) !== null) return false;
+      return Number(d2[tag_members_fractions[geometry]]) > 0;
     };
   }
-  function valKey(d) {
+  function valKey(d2) {
     return {
-      value: d.key,
-      title: d.key
+      value: d2.key,
+      title: d2.key
     };
   }
-  function valKeyDescription(d) {
+  function valKeyDescription(d2) {
     var obj = {
-      value: d.value,
-      title: d.description || d.value
+      value: d2.value,
+      title: d2.description || d2.value
     };
     return obj;
   }
-  function roleKey(d) {
+  function roleKey(d2) {
     return {
-      value: d.role,
-      title: d.role
+      value: d2.role,
+      title: d2.role
     };
   }
-  function sortKeys(a, b) {
-    return a.key.indexOf(":") === -1 && b.key.indexOf(":") !== -1 ? -1 : a.key.indexOf(":") !== -1 && b.key.indexOf(":") === -1 ? 1 : 0;
+  function sortKeys(a2, b2) {
+    return a2.key.indexOf(":") === -1 && b2.key.indexOf(":") !== -1 ? -1 : a2.key.indexOf(":") !== -1 && b2.key.indexOf(":") === -1 ? 1 : 0;
   }
   var debouncedRequest2 = debounce_default(request2, 300, { leading: false });
   function request2(url, params, exactMatch, callback, loaded) {
-    if (_inflight3[url])
-      return;
-    if (checkCache(url, params, exactMatch, callback))
-      return;
+    if (_inflight3[url]) return;
+    if (checkCache(url, params, exactMatch, callback)) return;
     var controller = new AbortController();
     _inflight3[url] = controller;
     json_default(url, { signal: controller.signal }).then(function(result) {
       delete _inflight3[url];
-      if (loaded)
-        loaded(null, result);
+      if (loaded) loaded(null, result);
     }).catch(function(err) {
       delete _inflight3[url];
-      if (err.name === "AbortError")
-        return;
-      if (loaded)
-        loaded(err.message);
+      if (err.name === "AbortError") return;
+      if (loaded) loaded(err.message);
     });
   }
   function checkCache(url, params, exactMatch, callback) {
@@ -73175,8 +79984,7 @@ ${content}</tr>
         callback(null, hit);
         return true;
       }
-      if (exactMatch || !testQuery.length)
-        return false;
+      if (exactMatch || !testQuery.length) return false;
       testQuery = testQuery.slice(0, -1);
       testUrl = url.replace(/&query=(.*?)&/, "&query=" + testQuery + "&");
     } while (testQuery.length >= 0);
@@ -73187,6 +79995,7 @@ ${content}</tr>
       _inflight3 = {};
       _taginfoCache = {};
       _popularKeys = {
+        // manually exclude some keys – #5377, #7485
         postal_code: true,
         full_name: true,
         loc_name: true,
@@ -73208,12 +80017,10 @@ ${content}</tr>
         lang: _mainLocalizer.languageCode()
       };
       this.keys(params, function(err, data) {
-        if (err)
-          return;
-        data.forEach(function(d) {
-          if (d.value === "opening_hours")
-            return;
-          _popularKeys[d.value] = true;
+        if (err) return;
+        data.forEach(function(d2) {
+          if (d2.value === "opening_hours") return;
+          _popularKeys[d2.value] = true;
         });
       });
     },
@@ -73234,12 +80041,12 @@ ${content}</tr>
         lang: _mainLocalizer.languageCode()
       }, params);
       var url = apibase4 + "keys/all?" + utilQsString(params);
-      doRequest(url, params, false, callback, function(err, d) {
+      doRequest(url, params, false, callback, function(err, d2) {
         if (err) {
           callback(err);
         } else {
           var f2 = filterKeys(params.filter);
-          var result = d.data.filter(f2).sort(sortKeys).map(valKey);
+          var result = d2.data.filter(f2).sort(sortKeys).map(valKey);
           _taginfoCache[url] = result;
           callback(null, result);
         }
@@ -73257,12 +80064,12 @@ ${content}</tr>
       }, params);
       var prefix = params.query;
       var url = apibase4 + "keys/all?" + utilQsString(params);
-      doRequest(url, params, true, callback, function(err, d) {
+      doRequest(url, params, true, callback, function(err, d2) {
         if (err) {
           callback(err);
         } else {
           var f2 = filterMultikeys(prefix);
-          var result = d.data.filter(f2).map(valKey);
+          var result = d2.data.filter(f2).map(valKey);
           _taginfoCache[url] = result;
           callback(null, result);
         }
@@ -73284,14 +80091,13 @@ ${content}</tr>
         lang: _mainLocalizer.languageCode()
       }, params);
       var url = apibase4 + "key/values?" + utilQsString(params);
-      doRequest(url, params, false, callback, function(err, d) {
+      doRequest(url, params, false, callback, function(err, d2) {
         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);
+          var result = d2.data.filter(f2).map(valKeyDescription);
           _taginfoCache[url] = result;
           callback(null, result);
         }
@@ -73309,12 +80115,12 @@ ${content}</tr>
         lang: _mainLocalizer.languageCode()
       }, params);
       var url = apibase4 + "relation/roles?" + utilQsString(params);
-      doRequest(url, params, true, callback, function(err, d) {
+      doRequest(url, params, true, callback, function(err, d2) {
         if (err) {
           callback(err);
         } else {
           var f2 = filterRoles(geometry);
-          var result = d.data.filter(f2).map(roleKey);
+          var result = d2.data.filter(f2).map(roleKey);
           _taginfoCache[url] = result;
           callback(null, result);
         }
@@ -73330,289 +80136,44 @@ ${content}</tr>
         path = "relation/wiki_pages?";
       }
       var url = apibase4 + path + utilQsString(params);
-      doRequest(url, params, true, callback, function(err, d) {
+      doRequest(url, params, true, callback, function(err, d2) {
         if (err) {
           callback(err);
         } else {
-          _taginfoCache[url] = d.data;
-          callback(null, d.data);
+          _taginfoCache[url] = d2.data;
+          callback(null, d2.data);
         }
       });
     },
-    apibase: function(_) {
-      if (!arguments.length)
-        return apibase4;
-      apibase4 = _;
+    apibase: function(_2) {
+      if (!arguments.length) return apibase4;
+      apibase4 = _2;
       return this;
     }
   };
 
   // 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());
-  var import_vector_tile2 = __toESM(require_vector_tile());
+  var import_polygon_clipping = __toESM(require_polygon_clipping_umd());
   var tiler7 = utilTiler().tileSize(512).margin(1);
-  var dispatch9 = dispatch_default("loadedData");
+  var dispatch11 = dispatch_default("loadedData");
   var _vtCache;
-  function abortRequest7(controller) {
+  function abortRequest6(controller) {
     controller.abort();
   }
   function vtToGeoJSON(data, tile, mergeCache) {
-    var vectorTile = new import_vector_tile2.default.VectorTile(new import_pbf2.default(data));
+    var vectorTile = new VectorTile(new Pbf(data));
     var layers = Object.keys(vectorTile.layers);
     if (!Array.isArray(layers)) {
       layers = [layers];
     }
-    var features2 = [];
+    var features = [];
     layers.forEach(function(layerID) {
       var layer = vectorTile.layers[layerID];
       if (layer) {
-        for (var i2 = 0; i2 < layer.length; i2++) {
-          var feature3 = layer.feature(i2).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        for (var i3 = 0; i3 < layer.length; i3++) {
+          var feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
           var geometry = feature3.geometry;
           if (geometry.type === "Polygon") {
             geometry.type = "MultiPolygon";
@@ -73620,26 +80181,24 @@ ${content}</tr>
           }
           var isClipped = false;
           if (geometry.type === "MultiPolygon") {
-            var featureClip = bboxClip(feature3, tile.extent.rectangle());
+            var featureClip = turf_bbox_clip_default(feature3, tile.extent.rectangle());
             if (!(0, import_fast_deep_equal11.default)(feature3.geometry, featureClip.geometry)) {
               isClipped = true;
             }
-            if (!feature3.geometry.coordinates.length)
-              continue;
-            if (!feature3.geometry.coordinates[0].length)
-              continue;
+            if (!feature3.geometry.coordinates.length) continue;
+            if (!feature3.geometry.coordinates[0].length) continue;
           }
           var featurehash = utilHashcode((0, import_fast_json_stable_stringify2.default)(feature3));
           var propertyhash = utilHashcode((0, import_fast_json_stable_stringify2.default)(feature3.properties || {}));
           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) {
               var other = merged[0];
-              var coords = import_polygon_clipping2.default.union(
+              var coords = import_polygon_clipping.default.union(
                 feature3.geometry.coordinates,
                 other.geometry.coordinates
               );
@@ -73658,13 +80217,12 @@ ${content}</tr>
         }
       }
     });
-    return features2;
+    return features;
   }
-  function loadTile2(source, tile) {
-    if (source.loaded[tile.id] || source.inflight[tile.id])
-      return;
-    var url = source.template.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function(s, r) {
-      var subdomains = r.split(",");
+  function loadTile3(source, tile) {
+    if (source.loaded[tile.id] || source.inflight[tile.id]) return;
+    var url = source.template.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function(s2, r2) {
+      var subdomains = r2.split(",");
       return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
     });
     var controller = new AbortController();
@@ -73680,12 +80238,12 @@ ${content}</tr>
       if (!data) {
         throw new Error("No Data");
       }
-      var z = tile.xyz[2];
-      if (!source.canMerge[z]) {
-        source.canMerge[z] = {};
+      var z2 = tile.xyz[2];
+      if (!source.canMerge[z2]) {
+        source.canMerge[z2] = {};
       }
-      source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
-      dispatch9.call("loadedData");
+      source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z2]);
+      dispatch11.call("loadedData");
     }).catch(function() {
       source.loaded[tile.id] = [];
       delete source.inflight[tile.id];
@@ -73696,13 +80254,13 @@ ${content}</tr>
       if (!_vtCache) {
         this.reset();
       }
-      this.event = utilRebind(this, dispatch9, "on");
+      this.event = utilRebind(this, dispatch11, "on");
     },
     reset: function() {
       for (var sourceID in _vtCache) {
         var source = _vtCache[sourceID];
         if (source && source.inflight) {
-          Object.values(source.inflight).forEach(abortRequest7);
+          Object.values(source.inflight).forEach(abortRequest6);
         }
       }
       _vtCache = {};
@@ -73713,20 +80271,17 @@ ${content}</tr>
     },
     data: function(sourceID, projection2) {
       var source = _vtCache[sourceID];
-      if (!source)
-        return [];
+      if (!source) return [];
       var tiles = tiler7.getTiles(projection2);
       var seen = {};
       var results = [];
-      for (var i2 = 0; i2 < tiles.length; i2++) {
-        var features2 = source.loaded[tiles[i2].id];
-        if (!features2 || !features2.length)
-          continue;
-        for (var j2 = 0; j2 < features2.length; j2++) {
-          var feature3 = features2[j2];
+      for (var i3 = 0; i3 < tiles.length; i3++) {
+        var features = source.loaded[tiles[i3].id];
+        if (!features || !features.length) continue;
+        for (var j2 = 0; j2 < features.length; j2++) {
+          var feature3 = features[j2];
           var hash = feature3.__featurehash__;
-          if (seen[hash])
-            continue;
+          if (seen[hash]) continue;
           seen[hash] = true;
           results.push(Object.assign({}, feature3));
         }
@@ -73739,17 +80294,17 @@ ${content}</tr>
         source = this.addSource(sourceID, template);
       }
       var tiles = tiler7.getTiles(projection2);
-      Object.keys(source.inflight).forEach(function(k) {
+      Object.keys(source.inflight).forEach(function(k2) {
         var wanted = tiles.find(function(tile) {
-          return k === tile.id;
+          return k2 === tile.id;
         });
         if (!wanted) {
-          abortRequest7(source.inflight[k]);
-          delete source.inflight[k];
+          abortRequest6(source.inflight[k2]);
+          delete source.inflight[k2];
         }
       });
       tiles.forEach(function(tile) {
-        loadTile2(source, tile);
+        loadTile3(source, tile);
       });
     },
     cache: function() {
@@ -73766,10 +80321,10 @@ ${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", {});
+        if (callback) callback("No query", {});
         return;
       }
       var lang = this.languagesToQuery()[0];
@@ -73779,26 +80334,32 @@ ${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 || {});
+        if (callback) callback(null, result.search || {});
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, {});
+        if (callback) callback(err.message, {});
       });
     },
+    // Given a Wikipedia language and article title,
+    // return an array of corresponding Wikidata entities.
     itemsByTitle: function(lang, title, callback) {
       if (!title) {
-        if (callback)
-          callback("No title", {});
+        if (callback) callback("No title", {});
         return;
       }
       lang = lang || "en";
@@ -73809,17 +80370,16 @@ ${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) {
         if (result && result.error) {
           throw new Error(result.error);
         }
-        if (callback)
-          callback(null, result.entities || {});
+        if (callback) callback(null, result.entities || {});
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, {});
+        if (callback) callback(err.message, {});
       });
     },
     languagesToQuery: function() {
@@ -73835,8 +80395,7 @@ ${content}</tr>
         return;
       }
       if (_wikidataCache[qid]) {
-        if (callback)
-          callback(null, _wikidataCache[qid]);
+        if (callback) callback(null, _wikidataCache[qid]);
         return;
       }
       var langs = this.languagesToQuery();
@@ -73846,8 +80405,8 @@ ${content}</tr>
         formatversion: 2,
         ids: qid,
         props: "labels|descriptions|claims|sitelinks",
-        sitefilter: langs.map(function(d) {
-          return d + "wiki";
+        sitefilter: langs.map(function(d2) {
+          return d2 + "wiki";
         }).join("|"),
         languages: langs.join("|"),
         languagefallback: 1,
@@ -73857,13 +80416,25 @@ ${content}</tr>
         if (result && result.error) {
           throw new Error(result.error);
         }
-        if (callback)
-          callback(null, result.entities[qid] || {});
+        if (callback) callback(null, result.entities[qid] || {});
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, {});
+        if (callback) callback(err.message, {});
       });
     },
+    // Pass `params` object of the form:
+    // {
+    //   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) {
@@ -73871,17 +80442,16 @@ ${content}</tr>
           callback(err || "No entity");
           return;
         }
-        var i2;
+        var i3;
         var description;
-        for (i2 in langs) {
-          let code = langs[i2];
+        for (i3 in langs) {
+          let code = langs[i3];
           if (entity.descriptions[code] && entity.descriptions[code].language === code) {
             description = entity.descriptions[code];
             break;
           }
         }
-        if (!description && Object.values(entity.descriptions).length)
-          description = Object.values(entity.descriptions)[0];
+        if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0];
         var result = {
           title: entity.id,
           description: description ? description.value : "",
@@ -73892,8 +80462,8 @@ ${content}</tr>
           var imageroot = "https://commons.wikimedia.org/w/index.php";
           var props = ["P154", "P18"];
           var prop, image;
-          for (i2 = 0; i2 < props.length; i2++) {
-            prop = entity.claims[props[i2]];
+          for (i3 = 0; i3 < props.length; i3++) {
+            prop = entity.claims[props[i3]];
             if (prop && Object.keys(prop).length > 0) {
               image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
               if (image) {
@@ -73908,18 +80478,18 @@ ${content}</tr>
         }
         if (entity.sitelinks) {
           var englishLocale = _mainLocalizer.languageCode().toLowerCase() === "en";
-          for (i2 = 0; i2 < langs.length; i2++) {
-            var w = langs[i2] + "wiki";
-            if (entity.sitelinks[w]) {
-              var title = entity.sitelinks[w].title;
+          for (i3 = 0; i3 < langs.length; i3++) {
+            var w2 = langs[i3] + "wiki";
+            if (entity.sitelinks[w2]) {
+              var title = entity.sitelinks[w2].title;
               var tKey = "inspector.wiki_reference";
-              if (!englishLocale && langs[i2] === "en") {
+              if (!englishLocale && langs[i3] === "en") {
                 tKey = "inspector.wiki_en_reference";
               }
               result.wiki = {
                 title,
                 text: tKey,
-                url: "https://" + langs[i2] + ".wikipedia.org/wiki/" + title.replace(/ /g, "_")
+                url: "https://" + langs[i3] + ".wikipedia.org/wiki/" + title.replace(/ /g, "_")
               };
               break;
             }
@@ -73939,8 +80509,7 @@ ${content}</tr>
     },
     search: function(lang, query, callback) {
       if (!query) {
-        if (callback)
-          callback("No Query", []);
+        if (callback) callback("No Query", []);
         return;
       }
       lang = lang || "en";
@@ -73960,20 +80529,18 @@ ${content}</tr>
           throw new Error("No Results");
         }
         if (callback) {
-          var titles = result.query.search.map(function(d) {
-            return d.title;
+          var titles = result.query.search.map(function(d2) {
+            return d2.title;
           });
           callback(null, titles);
         }
       }).catch(function(err) {
-        if (callback)
-          callback(err, []);
+        if (callback) callback(err, []);
       });
     },
     suggestions: function(lang, query, callback) {
       if (!query) {
-        if (callback)
-          callback("", []);
+        if (callback) callback("", []);
         return;
       }
       lang = lang || "en";
@@ -73991,17 +80558,14 @@ ${content}</tr>
         } else if (!result || result.length < 2) {
           throw new Error("No Results");
         }
-        if (callback)
-          callback(null, result[1] || []);
+        if (callback) callback(null, result[1] || []);
       }).catch(function(err) {
-        if (callback)
-          callback(err.message, []);
+        if (callback) callback(err.message, []);
       });
     },
     translations: function(lang, title, callback) {
       if (!title) {
-        if (callback)
-          callback("No Title");
+        if (callback) callback("No Title");
         return;
       }
       var url = endpoint.replace("en", lang) + utilQsString({
@@ -74019,31 +80583,864 @@ ${content}</tr>
           throw new Error("No Results");
         }
         if (callback) {
-          var list = result.query.pages[Object.keys(result.query.pages)[0]];
+          var list2 = result.query.pages[Object.keys(result.query.pages)[0]];
           var translations = {};
-          if (list && list.langlinks) {
-            list.langlinks.forEach(function(d) {
-              translations[d.lang] = d["*"];
+          if (list2 && list2.langlinks) {
+            list2.langlinks.forEach(function(d2) {
+              translations[d2.lang] = d2["*"];
             });
           }
           callback(null, translations);
         }
       }).catch(function(err) {
-        if (callback)
-          callback(err.message);
+        if (callback) callback(err.message);
       });
     }
   };
 
+  // modules/services/mapilio.js
+  var apiUrl2 = "https://end.mapilio.com";
+  var imageBaseUrl = "https://cdn.mapilio.com/im";
+  var baseTileUrl2 = "https://geo.mapilio.com/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=mapilio:";
+  var pointLayer = "map_points";
+  var lineLayer = "map_roads_line";
+  var tileStyle = "&STYLE=&TILEMATRIX=EPSG:900913:{z}&TILEMATRIXSET=EPSG:900913&FORMAT=application/vnd.mapbox-vector-tile&TILECOL={x}&TILEROW={y}";
+  var minZoom3 = 14;
+  var dispatch12 = dispatch_default("loadedImages", "loadedLines");
+  var imgZoom3 = zoom_default2().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
+  var pannellumViewerCSS3 = "pannellum/pannellum.css";
+  var pannellumViewerJS3 = "pannellum/pannellum.js";
+  var resolution = 1080;
+  var _activeImage;
+  var _cache3;
+  var _loadViewerPromise5;
+  var _pannellumViewer3;
+  var _sceneOptions2 = {
+    showFullscreenCtrl: false,
+    autoLoad: true,
+    yaw: 0,
+    minHfov: 10,
+    maxHfov: 90,
+    hfov: 60
+  };
+  var _currScene2 = 0;
+  function partitionViewport5(projection2) {
+    const z2 = geoScaleToZoom(projection2.scale());
+    const z22 = Math.ceil(z2 * 2) / 2 + 2.5;
+    const tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map(function(tile) {
+      return tile.extent;
+    });
+  }
+  function searchLimited5(limit, projection2, rtree) {
+    limit = limit || 5;
+    return partitionViewport5(projection2).reduce(function(result, extent) {
+      const found = rtree.search(extent.bbox()).slice(0, limit).map(function(d2) {
+        return d2.data;
+      });
+      return found.length ? result.concat(found) : result;
+    }, []);
+  }
+  function loadTiles4(which, url, maxZoom2, projection2) {
+    const tiler8 = utilTiler().zoomExtent([minZoom3, maxZoom2]).skipNullIsland(true);
+    const tiles = tiler8.getTiles(projection2);
+    tiles.forEach(function(tile) {
+      loadTile4(which, url, tile);
+    });
+  }
+  function loadTile4(which, url, tile) {
+    const cache = _cache3.requests;
+    const tileId = "".concat(tile.id, "-").concat(which);
+    if (cache.loaded[tileId] || cache.inflight[tileId]) return;
+    const controller = new AbortController();
+    cache.inflight[tileId] = controller;
+    const requestUrl = url.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace("{z}", tile.xyz[2]);
+    fetch(requestUrl, { signal: controller.signal }).then(function(response) {
+      if (!response.ok) {
+        throw new Error(response.status + " " + response.statusText);
+      }
+      cache.loaded[tileId] = true;
+      delete cache.inflight[tileId];
+      return response.arrayBuffer();
+    }).then(function(data) {
+      if (data.byteLength === 0) {
+        throw new Error("No Data");
+      }
+      loadTileDataToCache2(data, tile, which);
+      if (which === "images") {
+        dispatch12.call("loadedImages");
+      } else {
+        dispatch12.call("loadedLines");
+      }
+    }).catch(function(e3) {
+      if (e3.message === "No Data") {
+        cache.loaded[tileId] = true;
+      } else {
+        console.error(e3);
+      }
+    });
+  }
+  function loadTileDataToCache2(data, tile) {
+    const vectorTile = new VectorTile(new Pbf(data));
+    let features, cache, layer, i3, feature3, loc, d2;
+    if (vectorTile.layers.hasOwnProperty(pointLayer)) {
+      features = [];
+      cache = _cache3.images;
+      layer = vectorTile.layers[pointLayer];
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        let resolutionArr = feature3.properties.resolution.split("x");
+        let sourceWidth = Math.max(resolutionArr[0], resolutionArr[1]);
+        let sourceHeight = Math.min(resolutionArr[0], resolutionArr[1]);
+        let isPano = sourceWidth % sourceHeight === 0;
+        d2 = {
+          loc,
+          capture_time: feature3.properties.capture_time,
+          id: feature3.properties.id,
+          sequence_id: feature3.properties.sequence_uuid,
+          heading: feature3.properties.heading,
+          resolution: feature3.properties.resolution,
+          isPano
+        };
+        cache.forImageId[d2.id] = d2;
+        features.push({
+          minX: loc[0],
+          minY: loc[1],
+          maxX: loc[0],
+          maxY: loc[1],
+          data: d2
+        });
+      }
+      if (cache.rtree) {
+        cache.rtree.load(features);
+      }
+    }
+    if (vectorTile.layers.hasOwnProperty(lineLayer)) {
+      cache = _cache3.sequences;
+      layer = vectorTile.layers[lineLayer];
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        if (cache.lineString[feature3.properties.sequence_uuid]) {
+          cache.lineString[feature3.properties.sequence_uuid].push(feature3);
+        } else {
+          cache.lineString[feature3.properties.sequence_uuid] = [feature3];
+        }
+      }
+    }
+  }
+  function getImageData(imageId, sequenceId) {
+    return fetch(apiUrl2 + "/api/sequence-detail?sequence_uuid=".concat(sequenceId), { method: "GET" }).then(function(response) {
+      if (!response.ok) {
+        throw new Error(response.status + " " + response.statusText);
+      }
+      return response.json();
+    }).then(function(data) {
+      let index = data.data.findIndex((feature3) => feature3.id === imageId);
+      const { filename, uploaded_hash } = data.data[index];
+      _sceneOptions2.panorama = imageBaseUrl + "/" + uploaded_hash + "/" + filename + "/" + resolution;
+    });
+  }
+  var mapilio_default = {
+    // Initialize Mapilio
+    init: function() {
+      if (!_cache3) {
+        this.reset();
+      }
+      this.event = utilRebind(this, dispatch12, "on");
+    },
+    // Reset cache and state
+    reset: function() {
+      if (_cache3) {
+        Object.values(_cache3.requests.inflight).forEach(function(request3) {
+          request3.abort();
+        });
+      }
+      _cache3 = {
+        images: { rtree: new RBush(), forImageId: {} },
+        sequences: { rtree: new RBush(), lineString: {} },
+        requests: { loaded: {}, inflight: {} }
+      };
+      _activeImage = null;
+    },
+    // Get visible images
+    images: function(projection2) {
+      const limit = 5;
+      return searchLimited5(limit, projection2, _cache3.images.rtree);
+    },
+    cachedImage: function(imageKey) {
+      return _cache3.images.forImageId[imageKey];
+    },
+    // Load images in the visible area
+    loadImages: function(projection2) {
+      let url = baseTileUrl2 + pointLayer + tileStyle;
+      loadTiles4("images", url, 14, projection2);
+    },
+    // Load line in the visible area
+    loadLines: function(projection2) {
+      let url = baseTileUrl2 + lineLayer + tileStyle;
+      loadTiles4("line", url, 14, projection2);
+    },
+    // 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 = [];
+      _cache3.images.rtree.search(bbox2).forEach(function(d2) {
+        if (d2.data.sequence_id) {
+          sequenceIds[d2.data.sequence_id] = true;
+        }
+      });
+      Object.keys(sequenceIds).forEach(function(sequenceId) {
+        if (_cache3.sequences.lineString[sequenceId]) {
+          lineStrings = lineStrings.concat(_cache3.sequences.lineString[sequenceId]);
+        }
+      });
+      return lineStrings;
+    },
+    // Set the currently visible image
+    setActiveImage: function(image) {
+      if (image) {
+        _activeImage = {
+          id: image.id,
+          sequence_id: image.sequence_id
+        };
+      } else {
+        _activeImage = 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 = _activeImage && _activeImage.sequence_id;
+      const selectedImageId = _activeImage && _activeImage.id;
+      const markers = context.container().selectAll(".layer-mapilio .viewfield-group");
+      const sequences = context.container().selectAll(".layer-mapilio .sequence");
+      markers.classed("highlighted", function(d2) {
+        return d2.id === hoveredImageId;
+      }).classed("hovered", function(d2) {
+        return d2.id === hoveredImageId;
+      }).classed("currentView", function(d2) {
+        return d2.id === selectedImageId;
+      });
+      sequences.classed("highlighted", function(d2) {
+        return d2.properties.sequence_uuid === hoveredSequenceId;
+      }).classed("currentView", function(d2) {
+        return d2.properties.sequence_uuid === selectedSequenceId;
+      });
+      return this;
+    },
+    updateUrlImage: function(imageKey) {
+      if (!window.mocha) {
+        var hash = utilStringQs(window.location.hash);
+        if (imageKey) {
+          hash.photo = "mapilio/" + imageKey;
+        } else {
+          delete hash.photo;
+        }
+        window.location.replace("#" + utilQsString(hash, true));
+      }
+    },
+    initViewer: function() {
+      if (!window.pannellum) return;
+      if (_pannellumViewer3) return;
+      _currScene2 += 1;
+      const sceneID = _currScene2.toString();
+      const options2 = {
+        "default": { firstScene: sceneID },
+        scenes: {}
+      };
+      options2.scenes[sceneID] = _sceneOptions2;
+      _pannellumViewer3 = window.pannellum.viewer("ideditor-viewer-mapilio-pnlm", options2);
+    },
+    selectImage: function(context, id2) {
+      let that = this;
+      let d2 = this.cachedImage(id2);
+      this.setActiveImage(d2);
+      this.updateUrlImage(d2.id);
+      let viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) viewer.datum(d2);
+      this.setStyles(context, null);
+      if (!d2) return this;
+      let wrap2 = context.container().select(".photoviewer .mapilio-wrapper");
+      let attribution = wrap2.selectAll(".photo-attribution").text("");
+      if (d2.capture_time) {
+        attribution.append("span").attr("class", "captured_at").text(localeDateString2(d2.capture_time));
+        attribution.append("span").text("|");
+      }
+      attribution.append("a").attr("class", "image-link").attr("target", "_blank").attr("href", "https://mapilio.com/app?lat=".concat(d2.loc[1], "&lng=").concat(d2.loc[0], "&zoom=17&pId=").concat(d2.id)).text("mapilio.com");
+      wrap2.transition().duration(100).call(imgZoom3.transform, identity2);
+      wrap2.selectAll("img").remove();
+      wrap2.selectAll("button.back").classed("hide", !_cache3.images.forImageId.hasOwnProperty(+id2 - 1));
+      wrap2.selectAll("button.forward").classed("hide", !_cache3.images.forImageId.hasOwnProperty(+id2 + 1));
+      getImageData(d2.id, d2.sequence_id).then(function() {
+        if (d2.isPano) {
+          if (!_pannellumViewer3) {
+            that.initViewer();
+          } else {
+            _currScene2 += 1;
+            let sceneID = _currScene2.toString();
+            _pannellumViewer3.addScene(sceneID, _sceneOptions2).loadScene(sceneID);
+            if (_currScene2 > 2) {
+              sceneID = (_currScene2 - 1).toString();
+              _pannellumViewer3.removeScene(sceneID);
+            }
+          }
+        } else {
+          that.initOnlyPhoto(context);
+        }
+      });
+      function localeDateString2(s2) {
+        if (!s2) return null;
+        var options2 = { day: "numeric", month: "short", year: "numeric" };
+        var d4 = new Date(s2);
+        if (isNaN(d4.getTime())) return null;
+        return d4.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+      }
+      return this;
+    },
+    initOnlyPhoto: function(context) {
+      if (_pannellumViewer3) {
+        _pannellumViewer3.destroy();
+        _pannellumViewer3 = null;
+      }
+      let wrap2 = context.container().select("#ideditor-viewer-mapilio-simple");
+      let imgWrap = wrap2.select("img");
+      if (!imgWrap.empty()) {
+        imgWrap.attr("src", _sceneOptions2.panorama);
+      } else {
+        wrap2.append("img").attr("src", _sceneOptions2.panorama);
+      }
+    },
+    ensureViewerLoaded: function(context) {
+      let that = this;
+      let imgWrap = context.container().select("#ideditor-viewer-mapilio-simple > img");
+      if (!imgWrap.empty()) {
+        imgWrap.remove();
+      }
+      if (_loadViewerPromise5) return _loadViewerPromise5;
+      let wrap2 = context.container().select(".photoviewer").selectAll(".mapilio-wrapper").data([0]);
+      let wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper mapilio-wrapper").classed("hide", true).on("dblclick.zoom", null);
+      wrapEnter.append("div").attr("class", "photo-attribution fillD");
+      const controlsEnter = wrapEnter.append("div").attr("class", "photo-controls-wrap").append("div").attr("class", "photo-controls-mapilio");
+      controlsEnter.append("button").classed("back", true).on("click.back", step(-1)).text("\u25C4");
+      controlsEnter.append("button").classed("forward", true).on("click.forward", step(1)).text("\u25BA");
+      wrapEnter.append("div").attr("id", "ideditor-viewer-mapilio-pnlm");
+      wrapEnter.append("div").attr("id", "ideditor-viewer-mapilio-simple-wrap").call(imgZoom3.on("zoom", zoomPan2)).append("div").attr("id", "ideditor-viewer-mapilio-simple");
+      context.ui().photoviewer.on("resize.mapilio", () => {
+        if (_pannellumViewer3) {
+          _pannellumViewer3.resize();
+        }
+      });
+      _loadViewerPromise5 = new Promise((resolve, reject) => {
+        let loadedCount = 0;
+        function loaded() {
+          loadedCount += 1;
+          if (loadedCount === 2) resolve();
+        }
+        const head = select_default2("head");
+        head.selectAll("#ideditor-mapilio-viewercss").data([0]).enter().append("link").attr("id", "ideditor-mapilio-viewercss").attr("rel", "stylesheet").attr("crossorigin", "anonymous").attr("href", context.asset(pannellumViewerCSS3)).on("load.serviceMapilio", loaded).on("error.serviceMapilio", function() {
+          reject();
+        });
+        head.selectAll("#ideditor-mapilio-viewerjs").data([0]).enter().append("script").attr("id", "ideditor-mapilio-viewerjs").attr("crossorigin", "anonymous").attr("src", context.asset(pannellumViewerJS3)).on("load.serviceMapilio", loaded).on("error.serviceMapilio", function() {
+          reject();
+        });
+      }).catch(function() {
+        _loadViewerPromise5 = null;
+      });
+      function step(stepBy) {
+        return function() {
+          if (!_activeImage) return;
+          const imageId = _activeImage.id;
+          const nextIndex = imageId + stepBy;
+          if (!nextIndex) return;
+          const nextImage = _cache3.images.forImageId[nextIndex];
+          context.map().centerEase(nextImage.loc);
+          that.selectImage(context, nextImage.id);
+        };
+      }
+      function zoomPan2(d3_event) {
+        var t2 = d3_event.transform;
+        context.container().select(".photoviewer #ideditor-viewer-mapilio-simple").call(utilSetTransform, t2.x, t2.y, t2.k);
+      }
+      return _loadViewerPromise5;
+    },
+    showViewer: function(context) {
+      let wrap2 = context.container().select(".photoviewer").classed("hide", false);
+      let isHidden = wrap2.selectAll(".photo-wrapper.mapilio-wrapper.hide").size();
+      if (isHidden) {
+        wrap2.selectAll(".photo-wrapper:not(.mapilio-wrapper)").classed("hide", true);
+        wrap2.selectAll(".photo-wrapper.mapilio-wrapper").classed("hide", false);
+      }
+      return this;
+    },
+    /**
+     * hideViewer()
+     */
+    hideViewer: function(context) {
+      let viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) viewer.datum(null);
+      this.updateUrlImage(null);
+      viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
+      context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
+      this.setActiveImage();
+      return this.setStyles(context, null);
+    },
+    // Return the current cache
+    cache: function() {
+      return _cache3;
+    }
+  };
+
+  // modules/services/panoramax.js
+  var apiUrl3 = "https://api.panoramax.xyz/";
+  var tileUrl2 = apiUrl3 + "api/map/{z}/{x}/{y}.mvt";
+  var imageDataUrl = apiUrl3 + "api/collections/{collectionId}/items/{itemId}";
+  var userIdUrl = apiUrl3 + "api/users/search?q={username}";
+  var usernameURL = apiUrl3 + "api/users/{userId}";
+  var viewerUrl = apiUrl3;
+  var highDefinition = "hd";
+  var standardDefinition = "sd";
+  var pictureLayer = "pictures";
+  var sequenceLayer = "sequences";
+  var minZoom4 = 10;
+  var imageMinZoom = 15;
+  var lineMinZoom = 10;
+  var dispatch13 = dispatch_default("loadedImages", "loadedLines", "viewerChanged");
+  var _cache4;
+  var _loadViewerPromise6;
+  var _definition = standardDefinition;
+  var _isHD = false;
+  var _planeFrame2;
+  var _pannellumFrame2;
+  var _currentFrame2;
+  var _oldestDate;
+  var _currentScene = {
+    currentImage: null,
+    nextImage: null,
+    prevImage: null
+  };
+  var _activeImage2;
+  function partitionViewport6(projection2) {
+    const z2 = geoScaleToZoom(projection2.scale());
+    const z22 = Math.ceil(z2 * 2) / 2 + 2.5;
+    const tiler8 = utilTiler().zoomExtent([z22, z22]);
+    return tiler8.getTiles(projection2).map(function(tile) {
+      return tile.extent;
+    });
+  }
+  function searchLimited6(limit, projection2, rtree) {
+    limit = limit || 5;
+    return partitionViewport6(projection2).reduce(function(result, extent) {
+      let found = rtree.search(extent.bbox());
+      const spacing = Math.max(1, Math.floor(found.length / limit));
+      found = found.filter((d2, idx) => idx % spacing === 0 || d2.data.id === (_activeImage2 == null ? void 0 : _activeImage2.id)).sort((a2, b2) => {
+        if (a2.data.id === (_activeImage2 == null ? void 0 : _activeImage2.id)) return -1;
+        if (b2.data.id === (_activeImage2 == null ? void 0 : _activeImage2.id)) return 1;
+        return 0;
+      }).slice(0, limit).map((d2) => d2.data);
+      return found.length ? result.concat(found) : result;
+    }, []);
+  }
+  function loadTiles5(which, url, maxZoom2, projection2, zoom) {
+    const tiler8 = utilTiler().zoomExtent([minZoom4, maxZoom2]).skipNullIsland(true);
+    const tiles = tiler8.getTiles(projection2);
+    tiles.forEach(function(tile) {
+      loadTile5(which, url, tile, zoom);
+    });
+  }
+  function loadTile5(which, url, tile, zoom) {
+    const cache = _cache4.requests;
+    const tileId = "".concat(tile.id, "-").concat(which);
+    if (cache.loaded[tileId] || cache.inflight[tileId]) return;
+    const controller = new AbortController();
+    cache.inflight[tileId] = controller;
+    const requestUrl = url.replace("{x}", tile.xyz[0]).replace("{y}", tile.xyz[1]).replace("{z}", tile.xyz[2]);
+    fetch(requestUrl, { signal: controller.signal }).then(function(response) {
+      if (!response.ok) {
+        throw new Error(response.status + " " + response.statusText);
+      }
+      cache.loaded[tileId] = true;
+      delete cache.inflight[tileId];
+      return response.arrayBuffer();
+    }).then(function(data) {
+      if (data.byteLength === 0) {
+        throw new Error("No Data");
+      }
+      loadTileDataToCache3(data, tile, zoom);
+      if (which === "images") {
+        dispatch13.call("loadedImages");
+      } else {
+        dispatch13.call("loadedLines");
+      }
+    }).catch(function(e3) {
+      if (e3.message === "No Data") {
+        cache.loaded[tileId] = true;
+      } else {
+        console.error(e3);
+      }
+    });
+  }
+  function loadTileDataToCache3(data, tile, zoom) {
+    const vectorTile = new VectorTile(new Pbf(data));
+    let features, cache, layer, i3, feature3, loc, d2;
+    if (vectorTile.layers.hasOwnProperty(pictureLayer)) {
+      features = [];
+      cache = _cache4.images;
+      layer = vectorTile.layers[pictureLayer];
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        loc = feature3.geometry.coordinates;
+        d2 = {
+          loc,
+          capture_time: feature3.properties.ts,
+          capture_time_parsed: new Date(feature3.properties.ts),
+          id: feature3.properties.id,
+          account_id: feature3.properties.account_id,
+          sequence_id: feature3.properties.sequences.split('"')[1],
+          heading: parseInt(feature3.properties.heading, 10),
+          image_path: "",
+          resolution: feature3.properties.resolution,
+          isPano: feature3.properties.type === "equirectangular",
+          model: feature3.properties.model
+        };
+        cache.forImageId[d2.id] = d2;
+        features.push({
+          minX: loc[0],
+          minY: loc[1],
+          maxX: loc[0],
+          maxY: loc[1],
+          data: d2
+        });
+        if (_oldestDate) {
+          if (d2.capture_time < _oldestDate) {
+            _oldestDate = d2.capture_time;
+          }
+        } else {
+          _oldestDate = d2.capture_time;
+        }
+      }
+      if (cache.rtree) {
+        cache.rtree.load(features);
+      }
+    }
+    if (vectorTile.layers.hasOwnProperty(sequenceLayer)) {
+      cache = _cache4.sequences;
+      if (zoom >= lineMinZoom && zoom < imageMinZoom) cache = _cache4.mockSequences;
+      layer = vectorTile.layers[sequenceLayer];
+      for (i3 = 0; i3 < layer.length; i3++) {
+        feature3 = layer.feature(i3).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
+        if (cache.lineString[feature3.properties.id]) {
+          cache.lineString[feature3.properties.id].push(feature3);
+        } else {
+          cache.lineString[feature3.properties.id] = [feature3];
+        }
+        if (_oldestDate) {
+          if (feature3.properties.date < _oldestDate) {
+            _oldestDate = feature3.properties.date;
+          }
+        } else {
+          _oldestDate = feature3.properties.date;
+        }
+      }
+    }
+  }
+  async function getImageData2(collection_id, image_id) {
+    const requestUrl = imageDataUrl.replace("{collectionId}", collection_id).replace("{itemId}", image_id);
+    const response = await fetch(requestUrl, { method: "GET" });
+    if (!response.ok) {
+      throw new Error(response.status + " " + response.statusText);
+    }
+    const data = await response.json();
+    return data;
+  }
+  async function getUsername(user_id) {
+    const requestUrl = usernameURL.replace("{userId}", user_id);
+    const response = await fetch(requestUrl, { method: "GET" });
+    if (!response.ok) {
+      throw new Error(response.status + " " + response.statusText);
+    }
+    const data = await response.json();
+    return data.name;
+  }
+  var panoramax_default = {
+    init: function() {
+      if (!_cache4) {
+        this.reset();
+      }
+      this.event = utilRebind(this, dispatch13, "on");
+    },
+    reset: function() {
+      if (_cache4) {
+        Object.values(_cache4.requests.inflight).forEach(function(request3) {
+          request3.abort();
+        });
+      }
+      _cache4 = {
+        images: { rtree: new RBush(), forImageId: {} },
+        sequences: { rtree: new RBush(), lineString: {} },
+        mockSequences: { rtree: new RBush(), lineString: {} },
+        requests: { loaded: {}, inflight: {} }
+      };
+      _currentScene.currentImage = null;
+      _activeImage2 = null;
+    },
+    // Get visible images
+    images: function(projection2) {
+      const limit = 5;
+      return searchLimited6(limit, projection2, _cache4.images.rtree);
+    },
+    cachedImage: function(imageKey) {
+      return _cache4.images.forImageId[imageKey];
+    },
+    // Load images in the visible area
+    loadImages: function(projection2) {
+      loadTiles5("images", tileUrl2, imageMinZoom, projection2);
+    },
+    // Load line in the visible area
+    loadLines: function(projection2, zoom) {
+      loadTiles5("line", tileUrl2, lineMinZoom, projection2, zoom);
+    },
+    getUserIds: async function(usernames) {
+      const requestUrls = usernames.map((username) => userIdUrl.replace("{username}", username));
+      const responses = await Promise.all(requestUrls.map((requestUrl) => fetch(requestUrl, { method: "GET" })));
+      if (responses.some((response) => !response.ok)) {
+        const response = responses.find((response2) => !response2.ok);
+        throw new Error(response.status + " " + response.statusText);
+      }
+      const data = await Promise.all(responses.map((response) => response.json()));
+      return data.flatMap((d2, i3) => d2.features.filter((f2) => f2.name === usernames[i3]).map((f2) => f2.id));
+    },
+    getOldestDate: function() {
+      return _oldestDate;
+    },
+    // Get visible sequences
+    sequences: function(projection2, zoom) {
+      const viewport = projection2.clipExtent();
+      const min3 = [viewport[0][0], viewport[1][1]];
+      const max3 = [viewport[1][0], viewport[0][1]];
+      const bbox2 = geoExtent(projection2.invert(min3), projection2.invert(max3)).bbox();
+      const sequenceIds = {};
+      let lineStrings = [];
+      if (zoom >= imageMinZoom) {
+        _cache4.images.rtree.search(bbox2).forEach(function(d2) {
+          if (d2.data.sequence_id) {
+            sequenceIds[d2.data.sequence_id] = true;
+          }
+        });
+        Object.keys(sequenceIds).forEach(function(sequenceId) {
+          if (_cache4.sequences.lineString[sequenceId]) {
+            lineStrings = lineStrings.concat(_cache4.sequences.lineString[sequenceId]);
+          }
+        });
+        return lineStrings;
+      }
+      if (zoom >= lineMinZoom) {
+        Object.keys(_cache4.mockSequences.lineString).forEach(function(sequenceId) {
+          lineStrings = lineStrings.concat(_cache4.mockSequences.lineString[sequenceId]);
+        });
+      }
+      return lineStrings;
+    },
+    // Set the currently visible image
+    setActiveImage: function(image) {
+      if (image) {
+        _activeImage2 = {
+          id: image.id,
+          sequence_id: image.sequence_id
+        };
+      } else {
+        _activeImage2 = null;
+      }
+    },
+    getActiveImage: function() {
+      return _activeImage2;
+    },
+    // Update the currently highlighted sequence and selected bubble.
+    setStyles: function(context, hovered) {
+      const hoveredImageId = hovered && hovered.id;
+      const hoveredSequenceId = hovered && hovered.sequence_id;
+      const selectedSequenceId = _activeImage2 && _activeImage2.sequence_id;
+      const selectedImageId = _activeImage2 && _activeImage2.id;
+      const markers = context.container().selectAll(".layer-panoramax .viewfield-group");
+      const sequences = context.container().selectAll(".layer-panoramax .sequence");
+      markers.classed("highlighted", function(d2) {
+        return d2.sequence_id === selectedSequenceId || d2.id === hoveredImageId;
+      }).classed("hovered", function(d2) {
+        return d2.id === hoveredImageId;
+      }).classed("currentView", function(d2) {
+        return d2.id === selectedImageId;
+      });
+      sequences.classed("highlighted", function(d2) {
+        return d2.properties.id === hoveredSequenceId;
+      }).classed("currentView", function(d2) {
+        return d2.properties.id === selectedSequenceId;
+      });
+      context.container().selectAll(".layer-panoramax .viewfield-group .viewfield").attr("d", viewfieldPath);
+      function viewfieldPath() {
+        let d2 = this.parentNode.__data__;
+        if (d2.isPano && d2.id !== selectedImageId) {
+          return "M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0";
+        } else {
+          return "M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z";
+        }
+      }
+      return this;
+    },
+    updateUrlImage: function(imageKey) {
+      if (!window.mocha) {
+        var hash = utilStringQs(window.location.hash);
+        if (imageKey) {
+          hash.photo = "panoramax/" + imageKey;
+        } else {
+          delete hash.photo;
+        }
+        window.location.replace("#" + utilQsString(hash, true));
+      }
+    },
+    selectImage: function(context, id2) {
+      let that = this;
+      let d2 = that.cachedImage(id2);
+      that.setActiveImage(d2);
+      that.updateUrlImage(d2.id);
+      const viewerLink = "".concat(viewerUrl, "#pic=").concat(d2.id, "&focus=pic");
+      let viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) viewer.datum(d2);
+      this.setStyles(context, null);
+      if (!d2) return this;
+      let wrap2 = context.container().select(".photoviewer .panoramax-wrapper");
+      let attribution = wrap2.selectAll(".photo-attribution").text("");
+      let line1 = attribution.append("div").attr("class", "attribution-row");
+      const hdDomId = utilUniqueDomId("panoramax-hd");
+      let label = line1.append("label").attr("for", hdDomId).attr("class", "panoramax-hd");
+      label.append("input").attr("type", "checkbox").attr("id", hdDomId).property("checked", _isHD).on("click", (d3_event) => {
+        d3_event.stopPropagation();
+        _isHD = !_isHD;
+        _definition = _isHD ? highDefinition : standardDefinition;
+        that.selectImage(context, d2.id).showViewer(context);
+      });
+      label.append("span").call(_t.append("panoramax.hd"));
+      if (d2.capture_time) {
+        attribution.append("span").attr("class", "captured_at").text(localeDateString2(d2.capture_time));
+        attribution.append("span").text("|");
+      }
+      attribution.append("a").attr("class", "report-photo").attr("href", "mailto:signalement.ign@panoramax.fr").call(_t.append("panoramax.report"));
+      attribution.append("span").text("|");
+      attribution.append("a").attr("class", "image-link").attr("target", "_blank").attr("href", viewerLink).text("panoramax.xyz");
+      getImageData2(d2.sequence_id, d2.id).then(function(data) {
+        _currentScene = {
+          currentImage: null,
+          nextImage: null,
+          prevImage: null
+        };
+        _currentScene.currentImage = data.assets[_definition];
+        const nextIndex = data.links.findIndex((x2) => x2.rel === "next");
+        const prevIndex = data.links.findIndex((x2) => x2.rel === "prev");
+        if (nextIndex !== -1) {
+          _currentScene.nextImage = data.links[nextIndex];
+        }
+        if (prevIndex !== -1) {
+          _currentScene.prevImage = data.links[prevIndex];
+        }
+        d2.image_path = _currentScene.currentImage.href;
+        wrap2.selectAll("button.back").classed("hide", _currentScene.prevImage === null);
+        wrap2.selectAll("button.forward").classed("hide", _currentScene.nextImage === null);
+        _currentFrame2 = d2.isPano ? _pannellumFrame2 : _planeFrame2;
+        _currentFrame2.showPhotoFrame(wrap2).selectPhoto(d2, true);
+      });
+      function localeDateString2(s2) {
+        if (!s2) return null;
+        var options2 = { day: "numeric", month: "short", year: "numeric" };
+        var d4 = new Date(s2);
+        if (isNaN(d4.getTime())) return null;
+        return d4.toLocaleDateString(_mainLocalizer.localeCode(), options2);
+      }
+      if (d2.account_id) {
+        attribution.append("span").text("|");
+        let line2 = attribution.append("span").attr("class", "attribution-row");
+        getUsername(d2.account_id).then(function(username) {
+          line2.append("span").attr("class", "captured_by").text(_t("panoramax.captured_by", { username }));
+        });
+      }
+      return this;
+    },
+    photoFrame: function() {
+      return _currentFrame2;
+    },
+    ensureViewerLoaded: function(context) {
+      let that = this;
+      let imgWrap = context.container().select("#ideditor-viewer-panoramax-simple > img");
+      if (!imgWrap.empty()) {
+        imgWrap.remove();
+      }
+      if (_loadViewerPromise6) return _loadViewerPromise6;
+      let wrap2 = context.container().select(".photoviewer").selectAll(".panoramax-wrapper").data([0]);
+      let wrapEnter = wrap2.enter().append("div").attr("class", "photo-wrapper panoramax-wrapper").classed("hide", true).on("dblclick.zoom", null);
+      wrapEnter.append("div").attr("class", "photo-attribution fillD");
+      const controlsEnter = wrapEnter.append("div").attr("class", "photo-controls-wrap").append("div").attr("class", "photo-controls-panoramax");
+      controlsEnter.append("button").classed("back", true).on("click.back", step(-1)).text("\u25C4");
+      controlsEnter.append("button").classed("forward", true).on("click.forward", step(1)).text("\u25BA");
+      _loadViewerPromise6 = Promise.all([
+        pannellum_photo_default.init(context, wrapEnter),
+        plane_photo_default.init(context, wrapEnter)
+      ]).then(([pannellumPhotoFrame, planePhotoFrame]) => {
+        _pannellumFrame2 = pannellumPhotoFrame;
+        _pannellumFrame2.event.on("viewerChanged", () => dispatch13.call("viewerChanged"));
+        _planeFrame2 = planePhotoFrame;
+        _planeFrame2.event.on("viewerChanged", () => dispatch13.call("viewerChanged"));
+      });
+      function step(stepBy) {
+        return function() {
+          if (!_currentScene.currentImage) return;
+          let nextId;
+          if (stepBy === 1) nextId = _currentScene.nextImage.id;
+          else nextId = _currentScene.prevImage.id;
+          if (!nextId) return;
+          const nextImage = _cache4.images.forImageId[nextId];
+          if (nextImage) {
+            context.map().centerEase(nextImage.loc);
+            that.selectImage(context, nextImage.id);
+          }
+        };
+      }
+      return _loadViewerPromise6;
+    },
+    showViewer: function(context) {
+      let wrap2 = context.container().select(".photoviewer").classed("hide", false);
+      let isHidden = wrap2.selectAll(".photo-wrapper.panoramax-wrapper.hide").size();
+      if (isHidden) {
+        wrap2.selectAll(".photo-wrapper:not(.panoramax-wrapper)").classed("hide", true);
+        wrap2.selectAll(".photo-wrapper.panoramax-wrapper").classed("hide", false);
+      }
+      return this;
+    },
+    hideViewer: function(context) {
+      let viewer = context.container().select(".photoviewer");
+      if (!viewer.empty()) viewer.datum(null);
+      this.updateUrlImage(null);
+      viewer.classed("hide", true).selectAll(".photo-wrapper").classed("hide", true);
+      context.container().selectAll(".viewfield-group, .sequence, .icon-sign").classed("currentView", false);
+      this.setActiveImage();
+      return this.setStyles(context, null);
+    },
+    cache: function() {
+      return _cache4;
+    }
+  };
+
   // modules/services/index.js
   var services = {
     geocoder: nominatim_default,
     keepRight: keepRight_default,
-    improveOSM: improveOSM_default,
     osmose: osmose_default,
     mapillary: mapillary_default,
     nsi: nsi_default,
     kartaview: kartaview_default,
+    vegbilder: vegbilder_default,
     osm: osm_default,
     osmWikibase: osm_wikibase_default,
     maprules: maprules_default,
@@ -74051,7 +81448,9 @@ ${content}</tr>
     taginfo: taginfo_default,
     vectorTile: vector_tile_default,
     wikidata: wikidata_default,
-    wikipedia: wikipedia_default
+    wikipedia: wikipedia_default,
+    mapilio: mapilio_default,
+    panoramax: panoramax_default
   };
 
   // modules/modes/drag_note.js
@@ -74065,8 +81464,7 @@ ${content}</tr>
     var _lastLoc;
     var _note;
     function startNudge(d3_event, nudge) {
-      if (_nudgeInterval)
-        window.clearInterval(_nudgeInterval);
+      if (_nudgeInterval) window.clearInterval(_nudgeInterval);
       _nudgeInterval = window.setInterval(function() {
         context.map().pan(nudge);
         doMove(d3_event, nudge);
@@ -74161,8 +81559,7 @@ ${content}</tr>
       }
     }
     function esc() {
-      if (context.container().select(".combobox").size())
-        return;
+      if (context.container().select(".combobox").size()) return;
       context.enter(modeBrowse(context));
     }
     mode.zoomToSelected = function() {
@@ -74203,14 +81600,13 @@ ${content}</tr>
     function keydown(d3_event) {
       if (d3_event.keyCode === 32) {
         var activeNode = document.activeElement;
-        if (activeNode && (/* @__PURE__ */ new Set(["INPUT", "TEXTAREA"])).has(activeNode.nodeName))
-          return;
+        if (activeNode && (/* @__PURE__ */ new Set(["INPUT", "TEXTAREA"])).has(activeNode.nodeName)) return;
       }
-      if (d3_event.keyCode === 93 || d3_event.keyCode === 32) {
+      if (d3_event.keyCode === 93 || // context menu key
+      d3_event.keyCode === 32) {
         d3_event.preventDefault();
       }
-      if (d3_event.repeat)
-        return;
+      if (d3_event.repeat) return;
       cancelLongPress();
       if (d3_event.shiftKey) {
         context.surface().classed("behavior-multiselect", true);
@@ -74239,8 +81635,7 @@ ${content}</tr>
         var pointer = _downPointers.spacebar;
         if (pointer) {
           delete _downPointers.spacebar;
-          if (pointer.done)
-            return;
+          if (pointer.done) return;
           d3_event.preventDefault();
           _lastInteractionType = "spacebar";
           click(pointer.firstEvent, pointer.lastEvent, "spacebar");
@@ -74250,10 +81645,11 @@ ${content}</tr>
     function pointerdown(d3_event) {
       var id2 = (d3_event.pointerId || "mouse").toString();
       cancelLongPress();
-      if (d3_event.buttons && d3_event.buttons !== 1)
-        return;
+      if (d3_event.buttons && d3_event.buttons !== 1) return;
       context.ui().closeEditMenu();
-      _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
@@ -74261,10 +81657,9 @@ ${content}</tr>
     }
     function didLongPress(id2, interactionType) {
       var pointer = _downPointers[id2];
-      if (!pointer)
-        return;
-      for (var i2 in _downPointers) {
-        _downPointers[i2].done = true;
+      if (!pointer) return;
+      for (var i3 in _downPointers) {
+        _downPointers[i3].done = true;
       }
       _longPressTimeout = null;
       _lastInteractionType = interactionType;
@@ -74286,20 +81681,17 @@ ${content}</tr>
     function pointerup(d3_event) {
       var id2 = (d3_event.pointerId || "mouse").toString();
       var pointer = _downPointers[id2];
-      if (!pointer)
-        return;
+      if (!pointer) return;
       delete _downPointers[id2];
       if (_multiselectionPointerId === id2) {
         _multiselectionPointerId = null;
       }
-      if (pointer.done)
-        return;
+      if (pointer.done) return;
       click(pointer.firstEvent, d3_event, id2);
     }
     function pointercancel(d3_event) {
       var id2 = (d3_event.pointerId || "mouse").toString();
-      if (!_downPointers[id2])
-        return;
+      if (!_downPointers[id2]) return;
       delete _downPointers[id2];
       if (_multiselectionPointerId === id2) {
         _multiselectionPointerId = null;
@@ -74309,13 +81701,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 +81738,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();
@@ -74351,13 +81751,11 @@ ${content}</tr>
         var mode = context.mode();
         var selectedIDs = mode.id === "select" ? mode.selectedIDs() : [];
         for (var pointerId2 in _downPointers) {
-          if (pointerId2 === "spacebar" || pointerId2 === skipPointerId)
-            continue;
+          if (pointerId2 === "spacebar" || pointerId2 === skipPointerId) continue;
           var pointerInfo = _downPointers[pointerId2];
           var p12 = pointGetter(pointerInfo.firstEvent);
           var p22 = pointGetter(pointerInfo.lastEvent);
-          if (geoVecLength(p12, p22) > _tolerancePx)
-            continue;
+          if (geoVecLength(p12, p22) > _tolerancePx) continue;
           var datum2 = pointerInfo.firstEvent.target.__data__;
           var entity = datum2 && datum2.properties && datum2.properties.entity || datum2;
           if (context.graph().hasEntity(entity.id)) {
@@ -74376,8 +81774,7 @@ ${content}</tr>
       var showMenu = _showMenu;
       var interactionType = _lastInteractionType;
       var entity = datum2 && datum2.properties && datum2.properties.entity;
-      if (entity)
-        datum2 = entity;
+      if (entity) datum2 = entity;
       if (datum2 && datum2.type === "midpoint") {
         datum2 = datum2.parents[0];
       }
@@ -74388,8 +81785,7 @@ ${content}</tr>
         context.selectedErrorID(null);
         if (!isMultiselect) {
           if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum2.id) === -1) {
-            if (alsoSelectId === datum2.id)
-              alsoSelectId = null;
+            if (alsoSelectId === datum2.id) alsoSelectId = null;
             selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum2.id]);
             newMode = mode.id === "select" ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
             context.enter(newMode);
@@ -74423,13 +81819,11 @@ ${content}</tr>
         }
       }
       context.ui().closeEditMenu();
-      if (showMenu)
-        context.ui().showEditMenu(point, interactionType);
+      if (showMenu) context.ui().showEditMenu(point, interactionType);
       resetProperties();
     }
     function cancelLongPress() {
-      if (_longPressTimeout)
-        window.clearTimeout(_longPressTimeout);
+      if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
       _longPressTimeout = null;
     }
     function resetProperties() {
@@ -74441,8 +81835,8 @@ ${content}</tr>
       resetProperties();
       _lastMouseEvent = context.map().lastPointerEvent();
       select_default2(window).on("keydown.select", keydown).on("keyup.select", keyup).on(_pointerPrefix + "move.select", pointermove, true).on(_pointerPrefix + "up.select", pointerup, true).on("pointercancel.select", pointercancel, true).on("contextmenu.select-window", function(d3_event) {
-        var e = d3_event;
-        if (+e.clientX === 0 && +e.clientY === 0) {
+        var e3 = d3_event;
+        if (+e3.clientX === 0 && +e3.clientY === 0) {
           d3_event.preventDefault();
         }
       });
@@ -74497,19 +81891,19 @@ ${content}</tr>
       }) : [];
     }
     var _candidates = candidateWays();
-    var operation = function() {
+    var operation2 = function() {
       var candidate = _candidates[0];
       context.enter(
         modeDrawLine(context, candidate.id, context.graph(), "line", candidate.affix(_vertex.id), true)
       );
     };
-    operation.relatedEntityIds = function() {
+    operation2.relatedEntityIds = function() {
       return _candidates.length ? [_candidates[0].id] : [];
     };
-    operation.available = function() {
+    operation2.available = function() {
       return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       if (_candidates.length === 0) {
         return "not_eligible";
       } else if (_candidates.length > 1) {
@@ -74517,18 +81911,18 @@ ${content}</tr>
       }
       return false;
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
       return disable ? _t.append("operations.continue." + disable) : _t.append("operations.continue.description");
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       return _t("operations.continue.annotation.line");
     };
-    operation.id = "continue";
-    operation.keys = [_t("operations.continue.key")];
-    operation.title = _t.append("operations.continue.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "continue";
+    operation2.keys = [_t("operations.continue.key")];
+    operation2.title = _t.append("operations.continue.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/copy.js
@@ -74539,29 +81933,29 @@ ${content}</tr>
         return entity.hasInterestingTags() || entity.geometry(context.graph()) !== "vertex";
       });
     }
-    var operation = function() {
+    var operation2 = function() {
       var graph = context.graph();
       var selected = groupEntities(getFilteredIdsToCopy(), graph);
       var canCopy = [];
       var skip = {};
       var entity;
-      var i2;
-      for (i2 = 0; i2 < selected.relation.length; i2++) {
-        entity = selected.relation[i2];
+      var i3;
+      for (i3 = 0; i3 < selected.relation.length; i3++) {
+        entity = selected.relation[i3];
         if (!skip[entity.id] && entity.isComplete(graph)) {
           canCopy.push(entity.id);
           skip = getDescendants(entity.id, graph, skip);
         }
       }
-      for (i2 = 0; i2 < selected.way.length; i2++) {
-        entity = selected.way[i2];
+      for (i3 = 0; i3 < selected.way.length; i3++) {
+        entity = selected.way[i3];
         if (!skip[entity.id]) {
           canCopy.push(entity.id);
           skip = getDescendants(entity.id, graph, skip);
         }
       }
-      for (i2 = 0; i2 < selected.node.length; i2++) {
-        entity = selected.node[i2];
+      for (i3 = 0; i3 < selected.node.length; i3++) {
+        entity = selected.node[i3];
         if (!skip[entity.id]) {
           canCopy.push(entity.id);
         }
@@ -74587,53 +81981,53 @@ ${content}</tr>
       var children2;
       descendants = descendants || {};
       if (entity.type === "relation") {
-        children2 = entity.members.map(function(m) {
-          return m.id;
+        children2 = entity.members.map(function(m2) {
+          return m2.id;
         });
       } else if (entity.type === "way") {
         children2 = entity.nodes;
       } else {
         children2 = [];
       }
-      for (var i2 = 0; i2 < children2.length; i2++) {
-        if (!descendants[children2[i2]]) {
-          descendants[children2[i2]] = true;
-          descendants = getDescendants(children2[i2], graph, descendants);
+      for (var i3 = 0; i3 < children2.length; i3++) {
+        if (!descendants[children2[i3]]) {
+          descendants[children2[i3]] = true;
+          descendants = getDescendants(children2[i3], graph, descendants);
         }
       }
       return descendants;
     }
-    operation.available = function() {
+    operation2.available = function() {
       return getFilteredIdsToCopy().length > 0;
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
       if (extent.percentContainedIn(context.map().extent()) < 0.8) {
         return "too_large";
       }
       return false;
     };
-    operation.availableForKeypress = function() {
+    operation2.availableForKeypress = function() {
       var selection2 = window.getSelection && window.getSelection();
       return !selection2 || !selection2.toString();
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
       return disable ? _t.append("operations.copy." + disable, { n: selectedIDs.length }) : _t.append("operations.copy.description", { n: selectedIDs.length });
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       return _t("operations.copy.annotation", { n: selectedIDs.length });
     };
     var _point;
-    operation.point = function(val) {
+    operation2.point = function(val) {
       _point = val;
-      return operation;
+      return operation2;
     };
-    operation.id = "copy";
-    operation.keys = [uiCmd("\u2318C")];
-    operation.title = _t.append("operations.copy.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "copy";
+    operation2.keys = [uiCmd("\u2318C")];
+    operation2.title = _t.append("operations.copy.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/disconnect.js
@@ -74667,7 +82061,7 @@ ${content}</tr>
           action.limitWays(waysIDsForVertex);
         }
         _actions.push(action);
-        _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map((d) => d.id));
+        _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map((d2) => d2.id));
       });
       _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function(id2) {
         return _wayIDs.indexOf(id2) === -1;
@@ -74683,8 +82077,8 @@ ${content}</tr>
         return context.entity(id2);
       });
       var nodes = utilGetAllNodes(_wayIDs, context.graph());
-      _coords = nodes.map(function(n2) {
-        return n2.loc;
+      _coords = nodes.map(function(n3) {
+        return n3.loc;
       });
       var sharedActions = [];
       var sharedNodes = [];
@@ -74694,13 +82088,12 @@ ${content}</tr>
         var action = actionDisconnect(node.id).limitWays(_wayIDs);
         if (action.disabled(context.graph()) !== "not_connected") {
           var count = 0;
-          for (var i2 in ways) {
-            var way = ways[i2];
+          for (var i3 in ways) {
+            var way = ways[i3];
             if (way.nodes.indexOf(node.id) !== -1) {
               count += 1;
             }
-            if (count > 1)
-              break;
+            if (count > 1) break;
           }
           if (count > 1) {
             sharedActions.push(action);
@@ -74729,40 +82122,36 @@ ${content}</tr>
       }
     }
     var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
-    var operation = function() {
+    var operation2 = function() {
       context.perform(function(graph) {
         return _actions.reduce(function(graph2, action) {
           return action(graph2);
         }, graph);
-      }, operation.annotation());
+      }, operation2.annotation());
       context.validator().validate();
     };
-    operation.relatedEntityIds = function() {
+    operation2.relatedEntityIds = function() {
       if (_vertexIDs.length) {
         return _disconnectingWayIds;
       }
       return _disconnectingVertexIds;
     };
-    operation.available = function() {
-      if (_actions.length === 0)
-        return false;
-      if (_otherIDs.length !== 0)
-        return false;
+    operation2.available = function() {
+      if (_actions.length === 0) return false;
+      if (_otherIDs.length !== 0) return false;
       if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function(wayID) {
         return _vertexIDs.some(function(vertexID) {
           var way = context.entity(wayID);
           return way.nodes.indexOf(vertexID) !== -1;
         });
-      }))
-        return false;
+      })) return false;
       return true;
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       var reason;
       for (var actionIndex in _actions) {
         reason = _actions[actionIndex].disabled(context.graph());
-        if (reason)
-          return reason;
+        if (reason) return reason;
       }
       if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
         return "too_large." + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? "single" : "multiple");
@@ -74773,8 +82162,7 @@ ${content}</tr>
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = _coords.filter(function(loc) {
@@ -74790,18 +82178,18 @@ ${content}</tr>
         return false;
       }
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
       return disable ? _t.append("operations.disconnect." + disable) : _t.append("operations.disconnect.description." + _descriptionID);
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       return _t("operations.disconnect.annotation." + _annotationID);
     };
-    operation.id = "disconnect";
-    operation.keys = [_t("operations.disconnect.key")];
-    operation.title = _t.append("operations.disconnect.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "disconnect";
+    operation2.keys = [_t("operations.disconnect.key")];
+    operation2.title = _t.append("operations.disconnect.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/downgrade.js
@@ -74812,19 +82200,19 @@ ${content}</tr>
     function downgradeTypeForEntityIDs(entityIds) {
       var downgradeType;
       _affectedFeatureCount = 0;
-      for (var i2 in entityIds) {
-        var entityID = entityIds[i2];
-        var type3 = downgradeTypeForEntityID(entityID);
-        if (type3) {
+      for (var i3 in entityIds) {
+        var entityID = entityIds[i3];
+        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;
           }
         }
       }
@@ -74834,8 +82222,7 @@ ${content}</tr>
       var graph = context.graph();
       var entity = graph.entity(entityID);
       var preset = _mainPresetIndex.match(entity, graph);
-      if (!preset || preset.isFallback())
-        return null;
+      if (!preset || preset.isFallback()) return null;
       if (entity.type === "node" && preset.id !== "address" && Object.keys(entity.tags).some(function(key) {
         return key.match(/^addr:.{1,}/);
       })) {
@@ -74850,40 +82237,36 @@ ${content}</tr>
       }
       return null;
     }
-    var buildingKeysToKeep = ["architect", "building", "height", "layer", "source", "type", "wheelchair"];
+    var buildingKeysToKeep = ["architect", "building", "height", "layer", "nycdoitt:bin", "source", "type", "wheelchair"];
     var addressKeysToKeep = ["source"];
-    var operation = function() {
+    var operation2 = function() {
       context.perform(function(graph) {
-        for (var i2 in selectedIDs) {
-          var entityID = selectedIDs[i2];
-          var type3 = downgradeTypeForEntityID(entityID);
-          if (!type3)
-            continue;
+        for (var i3 in selectedIDs) {
+          var entityID = selectedIDs[i3];
+          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)
-              continue;
-            if (type3 === "building") {
-              if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/))
-                continue;
+            if (type2 === "address" && addressKeysToKeep.indexOf(key) !== -1) continue;
+            if (type2 === "building") {
+              if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
             }
-            if (type3 !== "generic") {
-              if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/))
-                continue;
+            if (type2 !== "generic") {
+              if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
             }
             delete tags[key];
           }
           graph = actionChangeTags(entityID, tags)(graph);
         }
         return graph;
-      }, operation.annotation());
+      }, operation2.annotation());
       context.validator().validate();
       context.enter(modeSelect(context, selectedIDs));
     };
-    operation.available = function() {
+    operation2.available = function() {
       return _downgradeType;
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       if (selectedIDs.some(hasWikidataTag)) {
         return "has_wikidata_tag";
       }
@@ -74893,11 +82276,11 @@ ${content}</tr>
         return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
       }
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
       return disable ? _t.append("operations.downgrade." + disable + "." + _multi) : _t.append("operations.downgrade.description." + _downgradeType);
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       var suffix;
       if (_downgradeType === "building_address") {
         suffix = "generic";
@@ -74906,11 +82289,11 @@ ${content}</tr>
       }
       return _t("operations.downgrade.annotation." + suffix, { n: _affectedFeatureCount });
     };
-    operation.id = "downgrade";
-    operation.keys = [uiCmd("\u232B")];
-    operation.title = _t.append("operations.downgrade.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "downgrade";
+    operation2.keys = [uiCmd("\u232B")];
+    operation2.title = _t.append("operations.downgrade.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/extract.js
@@ -74924,35 +82307,32 @@ ${content}</tr>
     var _actions = selectedIDs.map(function(entityID) {
       var graph = context.graph();
       var entity = graph.hasEntity(entityID);
-      if (!entity || !entity.hasInterestingTags())
-        return null;
-      if (entity.type === "node" && graph.parentWays(entity).length === 0)
-        return null;
+      if (!entity || !entity.hasInterestingTags()) return null;
+      if (entity.type === "node" && graph.parentWays(entity).length === 0) return null;
       if (entity.type !== "node") {
         var preset = _mainPresetIndex.match(entity, graph);
-        if (preset.geometry.indexOf("point") === -1)
-          return null;
+        if (preset.geometry.indexOf("point") === -1) return null;
       }
       _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
       return actionExtract(entityID, context.projection);
     }).filter(Boolean);
-    var operation = function() {
+    var operation2 = function() {
       var combinedAction = function(graph) {
         _actions.forEach(function(action) {
           graph = action(graph);
         });
         return graph;
       };
-      context.perform(combinedAction, operation.annotation());
+      context.perform(combinedAction, operation2.annotation());
       var extractedNodeIDs = _actions.map(function(action) {
         return action.getExtractedNodeID();
       });
       context.enter(modeSelect(context, extractedNodeIDs));
     };
-    operation.available = function() {
+    operation2.available = function() {
       return _actions.length && selectedIDs.length === _actions.length;
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
         return "too_large";
       } else if (selectedIDs.some(function(entityID) {
@@ -74962,22 +82342,22 @@ ${content}</tr>
       }
       return false;
     };
-    operation.tooltip = function() {
-      var disableReason = operation.disabled();
+    operation2.tooltip = function() {
+      var disableReason = operation2.disabled();
       if (disableReason) {
         return _t.append("operations.extract." + disableReason + "." + _amount);
       } else {
         return _t.append("operations.extract.description." + _geometryID + "." + _amount);
       }
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       return _t("operations.extract.annotation", { n: selectedIDs.length });
     };
-    operation.id = "extract";
-    operation.keys = [_t("operations.extract.key")];
-    operation.title = _t.append("operations.extract.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "extract";
+    operation2.keys = [_t("operations.extract.key")];
+    operation2.title = _t.append("operations.extract.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/merge.js
@@ -74985,55 +82365,45 @@ ${content}</tr>
     var _action = getAction();
     function getAction() {
       var join = actionJoin(selectedIDs);
-      if (!join.disabled(context.graph()))
-        return join;
-      var merge3 = actionMerge(selectedIDs);
-      if (!merge3.disabled(context.graph()))
-        return merge3;
+      if (!join.disabled(context.graph())) return join;
+      var merge2 = actionMerge(selectedIDs);
+      if (!merge2.disabled(context.graph())) return merge2;
       var mergePolygon = actionMergePolygon(selectedIDs);
-      if (!mergePolygon.disabled(context.graph()))
-        return mergePolygon;
+      if (!mergePolygon.disabled(context.graph())) return mergePolygon;
       var mergeNodes = actionMergeNodes(selectedIDs);
-      if (!mergeNodes.disabled(context.graph()))
-        return mergeNodes;
-      if (join.disabled(context.graph()) !== "not_eligible")
-        return join;
-      if (merge3.disabled(context.graph()) !== "not_eligible")
-        return merge3;
-      if (mergePolygon.disabled(context.graph()) !== "not_eligible")
-        return mergePolygon;
+      if (!mergeNodes.disabled(context.graph())) return mergeNodes;
+      if (join.disabled(context.graph()) !== "not_eligible") return join;
+      if (merge2.disabled(context.graph()) !== "not_eligible") return merge2;
+      if (mergePolygon.disabled(context.graph()) !== "not_eligible") return mergePolygon;
       return mergeNodes;
     }
-    var operation = function() {
-      if (operation.disabled())
-        return;
-      context.perform(_action, operation.annotation());
+    var operation2 = function() {
+      if (operation2.disabled()) return;
+      context.perform(_action, operation2.annotation());
       context.validator().validate();
       var resultIDs = selectedIDs.filter(context.hasEntity);
       if (resultIDs.length > 1) {
         var interestingIDs = resultIDs.filter(function(id2) {
           return context.entity(id2).hasInterestingTags();
         });
-        if (interestingIDs.length)
-          resultIDs = interestingIDs;
+        if (interestingIDs.length) resultIDs = interestingIDs;
       }
       context.enter(modeSelect(context, resultIDs));
     };
-    operation.available = function() {
+    operation2.available = function() {
       return selectedIDs.length >= 2;
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       var actionDisabled = _action.disabled(context.graph());
-      if (actionDisabled)
-        return actionDisabled;
+      if (actionDisabled) return actionDisabled;
       var osm = context.connection();
       if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
         return "too_many_vertices";
       }
       return false;
     };
-    operation.tooltip = function() {
-      var disabled = operation.disabled();
+    operation2.tooltip = function() {
+      var disabled = operation2.disabled();
       if (disabled) {
         if (disabled === "conflicting_relations") {
           return _t.append("operations.merge.conflicting_relations");
@@ -75048,25 +82418,23 @@ ${content}</tr>
       }
       return _t.append("operations.merge.description");
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       return _t("operations.merge.annotation", { n: selectedIDs.length });
     };
-    operation.id = "merge";
-    operation.keys = [_t("operations.merge.key")];
-    operation.title = _t.append("operations.merge.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "merge";
+    operation2.keys = [_t("operations.merge.key")];
+    operation2.title = _t.append("operations.merge.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/paste.js
   function operationPaste(context) {
     var _pastePoint;
-    var operation = function() {
-      if (!_pastePoint)
-        return;
+    var operation2 = function() {
+      if (!_pastePoint) return;
       var oldIDs = context.copyIDs();
-      if (!oldIDs.length)
-        return;
+      if (!oldIDs.length) return;
       var projection2 = context.projection;
       var extent = geoExtent();
       var oldGraph = context.copyGraph();
@@ -75092,20 +82460,20 @@ ${content}</tr>
       }
       var copyPoint = context.copyLonLat() && projection2(context.copyLonLat()) || projection2(extent.center());
       var delta = geoVecSubtract(_pastePoint, copyPoint);
-      context.replace(actionMove(newIDs, delta, projection2), operation.annotation());
+      context.replace(actionMove(newIDs, delta, projection2), operation2.annotation());
       context.enter(modeSelect(context, newIDs));
     };
-    operation.point = function(val) {
+    operation2.point = function(val) {
       _pastePoint = val;
-      return operation;
+      return operation2;
     };
-    operation.available = function() {
+    operation2.available = function() {
       return context.mode().id === "browse";
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       return !context.copyIDs().length;
     };
-    operation.tooltip = function() {
+    operation2.tooltip = function() {
       var oldGraph = context.copyGraph();
       var ids = context.copyIDs();
       if (!ids.length) {
@@ -75113,42 +82481,38 @@ ${content}</tr>
       }
       return _t.append("operations.paste.description", { feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph), n: ids.length });
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       var ids = context.copyIDs();
       return _t("operations.paste.annotation", { n: ids.length });
     };
-    operation.id = "paste";
-    operation.keys = [uiCmd("\u2318V")];
-    operation.title = _t.append("operations.paste.title");
-    return operation;
+    operation2.id = "paste";
+    operation2.keys = [uiCmd("\u2318V")];
+    operation2.title = _t.append("operations.paste.title");
+    return operation2;
   }
 
   // modules/operations/reverse.js
   function operationReverse(context, selectedIDs) {
-    var operation = function() {
+    var operation2 = function() {
       context.perform(function combinedReverseAction(graph) {
         actions().forEach(function(action) {
           graph = action(graph);
         });
         return graph;
-      }, operation.annotation());
+      }, operation2.annotation());
       context.validator().validate();
     };
     function actions(situation) {
       return selectedIDs.map(function(entityID) {
         var entity = context.hasEntity(entityID);
-        if (!entity)
-          return null;
+        if (!entity) return null;
         if (situation === "toolbar") {
-          if (entity.type === "way" && (!entity.isOneWay() && !entity.isSided()))
-            return null;
+          if (entity.type === "way" && (!entity.isOneWay() && !entity.isSided())) return null;
         }
         var geometry = entity.geometry(context.graph());
-        if (entity.type !== "node" && geometry !== "line")
-          return null;
+        if (entity.type !== "node" && geometry !== "line") return null;
         var action = actionReverse(entityID);
-        if (action.disabled(context.graph()))
-          return null;
+        if (action.disabled(context.graph())) return null;
         return action;
       }).filter(Boolean);
     }
@@ -75158,30 +82522,28 @@ ${content}</tr>
         var entity = context.hasEntity(act.entityID());
         return entity && entity.type === "node";
       }).length;
-      if (nodeActionCount === 0)
-        return "line";
-      if (nodeActionCount === acts.length)
-        return "point";
+      if (nodeActionCount === 0) return "line";
+      if (nodeActionCount === acts.length) return "point";
       return "feature";
     }
-    operation.available = function(situation) {
+    operation2.available = function(situation) {
       return actions(situation).length > 0;
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       return false;
     };
-    operation.tooltip = function() {
+    operation2.tooltip = function() {
       return _t.append("operations.reverse.description." + reverseTypeID());
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       var acts = actions();
       return _t("operations.reverse.annotation." + reverseTypeID(), { n: acts.length });
     };
-    operation.id = "reverse";
-    operation.keys = [_t("operations.reverse.key")];
-    operation.title = _t.append("operations.reverse.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "reverse";
+    operation2.keys = [_t("operations.reverse.key")];
+    operation2.title = _t.append("operations.reverse.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/split.js
@@ -75200,8 +82562,7 @@ ${content}</tr>
     var _waysAmount = "single";
     var _nodesAmount = _vertexIds.length === 1 ? "single" : "multiple";
     if (_isAvailable) {
-      if (_selectedWayIds.length)
-        _action.limitWays(_selectedWayIds);
+      if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
       _ways = _action.ways(context.graph());
       var geometries = {};
       _ways.forEach(function(way) {
@@ -75212,20 +82573,20 @@ ${content}</tr>
       }
       _waysAmount = _ways.length === 1 ? "single" : "multiple";
     }
-    var operation = function() {
-      var difference = context.perform(_action, operation.annotation());
-      var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function(id2) {
+    var operation2 = function() {
+      var difference2 = context.perform(_action, operation2.annotation());
+      var idsToSelect = _vertexIds.concat(difference2.extantIDs().filter(function(id2) {
         return context.entity(id2).type === "way";
       }));
       context.enter(modeSelect(context, idsToSelect));
     };
-    operation.relatedEntityIds = function() {
+    operation2.relatedEntityIds = function() {
       return _selectedWayIds.length ? [] : _ways.map((way) => way.id);
     };
-    operation.available = function() {
+    operation2.available = function() {
       return _isAvailable;
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       var reason = _action.disabled(context.graph());
       if (reason) {
         return reason;
@@ -75234,25 +82595,25 @@ ${content}</tr>
       }
       return false;
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
       return disable ? _t.append("operations.split." + disable) : _t.append("operations.split.description." + _geometry + "." + _waysAmount + "." + _nodesAmount + "_node");
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       return _t("operations.split.annotation." + _geometry, { n: _ways.length });
     };
-    operation.icon = function() {
+    operation2.icon = function() {
       if (_waysAmount === "multiple") {
         return "#iD-operation-split-multiple";
       } else {
         return "#iD-operation-split";
       }
     };
-    operation.id = "split";
-    operation.keys = [_t("operations.split.key")];
-    operation.title = _t.append("operations.split.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "split";
+    operation2.keys = [_t("operations.split.key")];
+    operation2.title = _t.append("operations.split.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/operations/straighten.js
@@ -75265,8 +82626,8 @@ ${content}</tr>
     });
     var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? "single" : "multiple";
     var _nodes = utilGetAllNodes(selectedIDs, context.graph());
-    var _coords = _nodes.map(function(n2) {
-      return n2.loc;
+    var _coords = _nodes.map(function(n3) {
+      return n3.loc;
     });
     var _extent = utilTotalExtent(selectedIDs, context.graph());
     var _action = chooseAction();
@@ -75278,8 +82639,8 @@ ${content}</tr>
       } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
         var startNodeIDs = [];
         var endNodeIDs = [];
-        for (var i2 = 0; i2 < selectedIDs.length; i2++) {
-          var entity = context.entity(selectedIDs[i2]);
+        for (var i3 = 0; i3 < selectedIDs.length; i3++) {
+          var entity = context.entity(selectedIDs[i3]);
           if (entity.type === "node") {
             continue;
           } else if (entity.type !== "way" || entity.isClosed()) {
@@ -75288,21 +82649,18 @@ ${content}</tr>
           startNodeIDs.push(entity.first());
           endNodeIDs.push(entity.last());
         }
-        startNodeIDs = startNodeIDs.filter(function(n2) {
-          return startNodeIDs.indexOf(n2) === startNodeIDs.lastIndexOf(n2);
+        startNodeIDs = startNodeIDs.filter(function(n3) {
+          return startNodeIDs.indexOf(n3) === startNodeIDs.lastIndexOf(n3);
         });
-        endNodeIDs = endNodeIDs.filter(function(n2) {
-          return endNodeIDs.indexOf(n2) === endNodeIDs.lastIndexOf(n2);
+        endNodeIDs = endNodeIDs.filter(function(n3) {
+          return endNodeIDs.indexOf(n3) === endNodeIDs.lastIndexOf(n3);
         });
-        if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2)
-          return null;
+        if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null;
         var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function(node) {
           return node.id;
         });
-        if (wayNodeIDs.length <= 2)
-          return null;
-        if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1))
-          return null;
+        if (wayNodeIDs.length <= 2) return null;
+        if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
         if (_nodeIDs.length) {
           _extent = utilTotalExtent(_nodeIDs, context.graph());
         }
@@ -75311,18 +82669,17 @@ ${content}</tr>
       }
       return null;
     }
-    function operation() {
-      if (!_action)
-        return;
-      context.perform(_action, operation.annotation());
+    function operation2() {
+      if (!_action) return;
+      context.perform(_action, operation2.annotation());
       window.setTimeout(function() {
         context.validator().validate();
       }, 300);
     }
-    operation.available = function() {
+    operation2.available = function() {
       return Boolean(_action);
     };
-    operation.disabled = function() {
+    operation2.disabled = function() {
       var reason = _action.disabled(context.graph());
       if (reason) {
         return reason;
@@ -75335,8 +82692,7 @@ ${content}</tr>
       }
       return false;
       function someMissing() {
-        if (context.inIntro())
-          return false;
+        if (context.inIntro()) return false;
         var osm = context.connection();
         if (osm) {
           var missing = _coords.filter(function(loc) {
@@ -75352,18 +82708,18 @@ ${content}</tr>
         return false;
       }
     };
-    operation.tooltip = function() {
-      var disable = operation.disabled();
+    operation2.tooltip = function() {
+      var disable = operation2.disabled();
       return disable ? _t.append("operations.straighten." + disable + "." + _amount) : _t.append("operations.straighten.description." + _geometry + (_wayIDs.length === 1 ? "" : "s"));
     };
-    operation.annotation = function() {
+    operation2.annotation = function() {
       return _t("operations.straighten.annotation." + _geometry, { n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length });
     };
-    operation.id = "straighten";
-    operation.keys = [_t("operations.straighten.key")];
-    operation.title = _t.append("operations.straighten.title");
-    operation.behavior = behaviorOperation(context).which(operation);
-    return operation;
+    operation2.id = "straighten";
+    operation2.keys = [_t("operations.straighten.key")];
+    operation2.title = _t.append("operations.straighten.title");
+    operation2.behavior = behaviorOperation(context).which(operation2);
+    return operation2;
   }
 
   // modules/modes/select.js
@@ -75412,13 +82768,13 @@ ${content}</tr>
     function parentWaysIdsOfSelection(onlyCommonParents) {
       var graph = context.graph();
       var parents = [];
-      for (var i2 = 0; i2 < selectedIDs.length; i2++) {
-        var entity = context.hasEntity(selectedIDs[i2]);
+      for (var i3 = 0; i3 < selectedIDs.length; i3++) {
+        var entity = context.hasEntity(selectedIDs[i3]);
         if (!entity || entity.geometry(graph) !== "vertex") {
           return [];
         }
-        var currParents = graph.parentWays(entity).map(function(w) {
-          return w.id;
+        var currParents = graph.parentWays(entity).map(function(w2) {
+          return w2.id;
         });
         if (!parents.length) {
           parents = currParents;
@@ -75434,8 +82790,8 @@ ${content}</tr>
     function childNodeIdsOfSelection(onlyCommon) {
       var graph = context.graph();
       var childs = [];
-      for (var i2 = 0; i2 < selectedIDs.length; i2++) {
-        var entity = context.hasEntity(selectedIDs[i2]);
+      for (var i3 = 0; i3 < selectedIDs.length; i3++) {
+        var entity = context.hasEntity(selectedIDs[i3]);
         if (!entity || !["area", "line"].includes(entity.geometry(graph))) {
           return [];
         }
@@ -75456,8 +82812,7 @@ ${content}</tr>
     function checkFocusedParent() {
       if (_focusedParentWayId) {
         var parents = parentWaysIdsOfSelection(true);
-        if (parents.indexOf(_focusedParentWayId) === -1)
-          _focusedParentWayId = null;
+        if (parents.indexOf(_focusedParentWayId) === -1) _focusedParentWayId = null;
       }
     }
     function parentWayIdForVertexNavigation() {
@@ -75468,8 +82823,7 @@ ${content}</tr>
       return parentIds.length ? parentIds[0] : null;
     }
     mode.selectedIDs = function(val) {
-      if (!arguments.length)
-        return selectedIDs;
+      if (!arguments.length) return selectedIDs;
       selectedIDs = val;
       return mode;
     };
@@ -75477,43 +82831,41 @@ ${content}</tr>
       context.map().zoomToEase(selectedEntities());
     };
     mode.newFeature = function(val) {
-      if (!arguments.length)
-        return _newFeature;
+      if (!arguments.length) return _newFeature;
       _newFeature = val;
       return mode;
     };
     mode.selectBehavior = function(val) {
-      if (!arguments.length)
-        return _selectBehavior;
+      if (!arguments.length) return _selectBehavior;
       _selectBehavior = val;
       return mode;
     };
     mode.follow = function(val) {
-      if (!arguments.length)
-        return _follow;
+      if (!arguments.length) return _follow;
       _follow = val;
       return mode;
     };
     function loadOperations() {
-      _operations.forEach(function(operation) {
-        if (operation.behavior) {
-          context.uninstall(operation.behavior);
+      _operations.forEach(function(operation2) {
+        if (operation2.behavior) {
+          context.uninstall(operation2.behavior);
         }
       });
-      _operations = Object.values(operations_exports).map(function(o) {
-        return o(context, selectedIDs);
-      }).filter(function(o) {
-        return o.id !== "delete" && o.id !== "downgrade" && o.id !== "copy";
+      _operations = Object.values(operations_exports).map(function(o2) {
+        return o2(context, selectedIDs);
+      }).filter(function(o2) {
+        return o2.id !== "delete" && o2.id !== "downgrade" && o2.id !== "copy";
       }).concat([
+        // group copy/downgrade/delete operation together at the end of the list
         operationCopy(context, selectedIDs),
         operationDowngrade(context, selectedIDs),
         operationDelete(context, selectedIDs)
-      ]).filter(function(operation) {
-        return operation.available();
+      ]).filter(function(operation2) {
+        return operation2.available();
       });
-      _operations.forEach(function(operation) {
-        if (operation.behavior) {
-          context.install(operation.behavior);
+      _operations.forEach(function(operation2) {
+        if (operation2.behavior) {
+          context.install(operation2.behavior);
         }
       });
       context.ui().closeEditMenu();
@@ -75522,14 +82874,12 @@ ${content}</tr>
       return _operations;
     };
     mode.enter = function() {
-      if (!checkSelectedIDs())
-        return;
+      if (!checkSelectedIDs()) return;
       context.features().forceVisible(selectedIDs);
       _modeDragNode.restoreSelectedIDs(selectedIDs);
       loadOperations();
       if (!_behaviors.length) {
-        if (!_selectBehavior)
-          _selectBehavior = behaviorSelect(context);
+        if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
         _behaviors = [
           behaviorPaste(context),
           _breatheBehavior,
@@ -75567,8 +82917,7 @@ ${content}</tr>
       }
       function nudgeSelection(delta) {
         return function() {
-          if (!context.map().withinEditableZoom())
-            return;
+          if (!context.map().withinEditableZoom()) return;
           var moveOp = operationMove(context, selectedIDs);
           if (moveOp.disabled()) {
             context.ui().flash.duration(4e3).iconName("#iD-operation-" + moveOp.id).iconClass("operation disabled").label(moveOp.tooltip())();
@@ -75580,12 +82929,10 @@ ${content}</tr>
       }
       function scaleSelection(factor) {
         return function() {
-          if (!context.map().withinEditableZoom())
-            return;
+          if (!context.map().withinEditableZoom()) return;
           let nodes = utilGetAllNodes(selectedIDs, context.graph());
           let isUp = factor > 1;
-          if (nodes.length <= 1)
-            return;
+          if (nodes.length <= 1) return;
           let extent2 = utilTotalExtent(selectedIDs, context.graph());
           function scalingDisabled() {
             if (tooSmall()) {
@@ -75599,19 +82946,17 @@ ${content}</tr>
             }
             return false;
             function tooSmall() {
-              if (isUp)
-                return false;
+              if (isUp) return false;
               let dLon = Math.abs(extent2[1][0] - extent2[0][0]);
               let dLat = Math.abs(extent2[1][1] - extent2[0][1]);
               return dLon < geoMetersToLon(1, extent2[1][1]) && dLat < geoMetersToLat(1);
             }
             function someMissing() {
-              if (context.inIntro())
-                return false;
+              if (context.inIntro()) return false;
               let osm = context.connection();
               if (osm) {
-                let missing = nodes.filter(function(n2) {
-                  return !osm.isDataLoaded(n2.loc);
+                let missing = nodes.filter(function(n3) {
+                  return !osm.isDataLoaded(n3.loc);
                 });
                 if (missing.length) {
                   missing.forEach(function(loc2) {
@@ -75640,13 +82985,11 @@ ${content}</tr>
         };
       }
       function didDoubleUp(d3_event, loc2) {
-        if (!context.map().withinEditableZoom())
-          return;
+        if (!context.map().withinEditableZoom()) return;
         var target = select_default2(d3_event.target);
         var datum2 = target.datum();
         var entity = datum2 && datum2.properties && datum2.properties.entity;
-        if (!entity)
-          return;
+        if (!entity) return;
         if (entity instanceof osmWay && target.classed("target")) {
           var choice = geoChooseEdge(context.graph().childNodes(entity), loc2, context.projection);
           var prev = entity.nodes[choice.index - 1];
@@ -75665,8 +83008,7 @@ ${content}</tr>
         }
       }
       function selectElements() {
-        if (!checkSelectedIDs())
-          return;
+        if (!checkSelectedIDs()) return;
         var surface = context.surface();
         surface.selectAll(".selected-member").classed("selected-member", false);
         surface.selectAll(".selected").classed("selected", false);
@@ -75676,13 +83018,17 @@ ${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);
         }
       }
       function esc() {
-        if (context.container().select(".combobox").size())
-          return;
+        if (context.container().select(".combobox").size()) return;
         context.enter(modeBrowse(context));
       }
       function firstVertex(d3_event) {
@@ -75723,16 +83069,15 @@ ${content}</tr>
         d3_event.preventDefault();
         var parentId = parentWayIdForVertexNavigation();
         _focusedParentWayId = parentId;
-        if (!parentId)
-          return;
+        if (!parentId) return;
         var way = context.entity(parentId);
-        var length = way.nodes.length;
+        var length2 = way.nodes.length;
         var curr = way.nodes.indexOf(selectedIDs[0]);
         var index = -1;
         if (curr > 0) {
           index = curr - 1;
         } else if (way.isClosed()) {
-          index = length - 2;
+          index = length2 - 2;
         }
         if (index !== -1) {
           context.enter(
@@ -75744,13 +83089,12 @@ ${content}</tr>
         d3_event.preventDefault();
         var parentId = parentWayIdForVertexNavigation();
         _focusedParentWayId = parentId;
-        if (!parentId)
-          return;
+        if (!parentId) return;
         var way = context.entity(parentId);
-        var length = way.nodes.length;
+        var length2 = way.nodes.length;
         var curr = way.nodes.indexOf(selectedIDs[0]);
         var index = -1;
-        if (curr < length - 1) {
+        if (curr < length2 - 1) {
           index = curr + 1;
         } else if (way.isClosed()) {
           index = 0;
@@ -75764,8 +83108,7 @@ ${content}</tr>
       function focusNextParent(d3_event) {
         d3_event.preventDefault();
         var parents = parentWaysIdsOfSelection(true);
-        if (!parents || parents.length < 2)
-          return;
+        if (!parents || parents.length < 2) return;
         var index = parents.indexOf(_focusedParentWayId);
         if (index < 0 || index > parents.length - 2) {
           _focusedParentWayId = parents[0];
@@ -75782,8 +83125,7 @@ ${content}</tr>
         d3_event.preventDefault();
         var currentSelectedIds = mode.selectedIDs();
         var parentIds = _focusedParentWayId ? [_focusedParentWayId] : parentWaysIdsOfSelection(false);
-        if (!parentIds.length)
-          return;
+        if (!parentIds.length) return;
         context.enter(
           mode.selectedIDs(parentIds)
         );
@@ -75793,10 +83135,8 @@ ${content}</tr>
         d3_event.preventDefault();
         var currentSelectedIds = mode.selectedIDs();
         var childIds = _focusedVertexIds ? _focusedVertexIds.filter((id2) => context.hasEntity(id2)) : childNodeIdsOfSelection(true);
-        if (!childIds || !childIds.length)
-          return;
-        if (currentSelectedIds.length === 1)
-          _focusedParentWayId = currentSelectedIds[0];
+        if (!childIds || !childIds.length) return;
+        if (currentSelectedIds.length === 1) _focusedParentWayId = currentSelectedIds[0];
         context.enter(
           mode.selectedIDs(childIds)
         );
@@ -75805,9 +83145,9 @@ ${content}</tr>
     mode.exit = function() {
       _newFeature = false;
       _focusedVertexIds = null;
-      _operations.forEach(function(operation) {
-        if (operation.behavior) {
-          context.uninstall(operation.behavior);
+      _operations.forEach(function(operation2) {
+        if (operation2.behavior) {
+          context.uninstall(operation2.behavior);
         }
       });
       _operations = [];
@@ -75824,8 +83164,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();
       }
@@ -75853,28 +83200,30 @@ ${content}</tr>
         }
         lasso.p(context.map().mouse());
       }
-      function normalize2(a, b) {
+      function normalize2(a2, b2) {
         return [
-          [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
-          [Math.max(a[0], b[0]), Math.max(a[1], b[1])]
+          [Math.min(a2[0], b2[0]), Math.min(a2[1], b2[1])],
+          [Math.max(a2[0], b2[0]), Math.max(a2[1], b2[1])]
         ];
       }
       function lassoed() {
-        if (!lasso)
-          return [];
+        if (!lasso) 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 [];
         }
         var bounds = lasso.extent().map(context.projection.invert);
         var extent = geoExtent(normalize2(bounds[0], bounds[1]));
-        var intersects = context.history().intersects(extent).filter(function(entity) {
+        var intersects2 = context.history().intersects(extent).filter(function(entity) {
           return entity.type === "node" && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
         });
-        intersects.sort(function(node1, node2) {
+        intersects2.sort(function(node1, node2) {
           var parents1 = graph.parentWays(node1);
           var parents2 = graph.parentWays(node2);
           if (parents1.length && parents2.length) {
@@ -75883,21 +83232,20 @@ ${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;
           }
           return node1.loc[0] - node2.loc[0];
         });
-        return intersects.map(function(entity) {
+        return intersects2.map(function(entity) {
           return entity.id;
         });
       }
       function pointerup() {
         select_default2(window).on(_pointerPrefix + "move.lasso", null).on(_pointerPrefix + "up.lasso", null);
-        if (!lasso)
-          return;
+        if (!lasso) return;
         var ids = lassoed();
         lasso.close();
         if (ids.length) {
@@ -75924,15 +83272,13 @@ ${content}</tr>
     var _selectBehavior;
     var _behaviors = [];
     mode.selectBehavior = function(val) {
-      if (!arguments.length)
-        return _selectBehavior;
+      if (!arguments.length) return _selectBehavior;
       _selectBehavior = val;
       return mode;
     };
     mode.enter = function() {
       if (!_behaviors.length) {
-        if (!_selectBehavior)
-          _selectBehavior = behaviorSelect(context);
+        if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
         _behaviors = [
           behaviorPaste(context),
           behaviorHover(context).on("hover", context.ui().sidebar.hover),
@@ -75959,10 +83305,9 @@ ${content}</tr>
         context.ui().sidebar.hide();
       }
     };
-    mode.sidebar = function(_) {
-      if (!arguments.length)
-        return sidebar;
-      sidebar = _;
+    mode.sidebar = function(_2) {
+      if (!arguments.length) return sidebar;
+      sidebar = _2;
       return mode;
     };
     mode.operations = function() {
@@ -75973,15 +83318,15 @@ ${content}</tr>
 
   // modules/behavior/add_way.js
   function behaviorAddWay(context) {
-    var dispatch10 = dispatch_default("start", "startFromWay", "startFromNode");
+    var dispatch14 = dispatch_default("start", "startFromWay", "startFromNode");
     var draw = behaviorDraw(context);
     function behavior(surface) {
       draw.on("click", function() {
-        dispatch10.apply("start", this, arguments);
+        dispatch14.apply("start", this, arguments);
       }).on("clickWay", function() {
-        dispatch10.apply("startFromWay", this, arguments);
+        dispatch14.apply("startFromWay", this, arguments);
       }).on("clickNode", function() {
-        dispatch10.apply("startFromNode", this, arguments);
+        dispatch14.apply("startFromNode", this, arguments);
       }).on("cancel", behavior.cancel).on("finish", behavior.cancel);
       context.map().dblclickZoomEnable(false);
       surface.call(draw);
@@ -75995,7 +83340,7 @@ ${content}</tr>
       }, 1e3);
       context.enter(modeBrowse(context));
     };
-    return utilRebind(behavior, dispatch10, "on");
+    return utilRebind(behavior, dispatch14, "on");
   }
 
   // modules/behavior/hash.js
@@ -76006,7 +83351,7 @@ ${content}</tr>
       var map2 = context.map();
       var center = map2.center();
       var zoom = map2.zoom();
-      var precision2 = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
+      var precision3 = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
       var oldParams = utilObjectOmit(
         utilStringQs(window.location.hash),
         ["comment", "source", "hashtags", "walkthrough"]
@@ -76018,8 +83363,10 @@ ${content}</tr>
       });
       if (selected.length) {
         newParams.id = selected.join(",");
+      } else if (context.selectedNoteID()) {
+        newParams.id = "note/".concat(context.selectedNoteID());
       }
-      newParams.map = zoom.toFixed(2) + "/" + center[1].toFixed(precision2) + "/" + center[0].toFixed(precision2);
+      newParams.map = zoom.toFixed(2) + "/" + center[1].toFixed(precision3) + "/" + center[0].toFixed(precision3);
       return Object.assign(oldParams, newParams);
     }
     function computedHash() {
@@ -76061,50 +83408,59 @@ ${content}</tr>
       return baseTitle;
     }
     function updateTitle(includeChangeCount) {
-      if (!context.setsDocumentTitle())
-        return;
+      if (!context.setsDocumentTitle()) return;
       var newTitle = computedTitle(includeChangeCount);
       if (document.title !== newTitle) {
         document.title = newTitle;
       }
     }
     function updateHashIfNeeded() {
-      if (context.inIntro())
-        return;
+      if (context.inIntro()) return;
       var latestHash = computedHash();
       if (_cachedHash !== latestHash) {
         _cachedHash = latestHash;
-        window.history.replaceState(null, computedTitle(false), latestHash);
-        updateTitle(true);
-        const q = utilStringQs(latestHash);
-        if (q.map) {
-          corePreferences("map-location", q.map);
+        window.history.replaceState(null, computedTitle(
+          false
+          /* includeChangeCount */
+        ), latestHash);
+        updateTitle(
+          true
+          /* includeChangeCount */
+        );
+        const q2 = utilStringQs(latestHash);
+        if (q2.map) {
+          corePreferences("map-location", q2.map);
         }
       }
     }
     var _throttledUpdate = throttle_default(updateHashIfNeeded, 500);
     var _throttledUpdateTitle = throttle_default(function() {
-      updateTitle(true);
+      updateTitle(
+        true
+        /* includeChangeCount */
+      );
     }, 500);
     function hashchange() {
-      if (window.location.hash === _cachedHash)
-        return;
+      if (window.location.hash === _cachedHash) return;
       _cachedHash = window.location.hash;
-      var q = utilStringQs(_cachedHash);
-      var mapArgs = (q.map || "").split("/").map(Number);
+      var q2 = utilStringQs(_cachedHash);
+      var mapArgs = (q2.map || "").split("/").map(Number);
       if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
         updateHashIfNeeded();
       } else {
-        if (_cachedHash === computedHash())
-          return;
+        if (_cachedHash === computedHash()) return;
         var mode = context.mode();
         context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
-        if (q.id && mode) {
-          var ids = q.id.split(",").filter(function(id2) {
-            return context.hasEntity(id2);
+        if (q2.id && mode) {
+          var ids = q2.id.split(",").filter(function(id2) {
+            return context.hasEntity(id2) || id2.startsWith("note/");
           });
-          if (ids.length && (mode.id === "browse" || mode.id === "select" && !utilArrayIdentical(mode.selectedIDs(), ids))) {
-            context.enter(modeSelect(context, ids));
+          if (ids.length && ["browse", "select-note", "select"].includes(mode.id)) {
+            if (ids.length === 1 && ids[0].startsWith("note/")) {
+              context.enter(modeSelectNote(context, ids[0]));
+            } else if (!utilArrayIdentical(mode.selectedIDs(), ids)) {
+              context.enter(modeSelect(context, ids));
+            }
             return;
           }
         }
@@ -76122,16 +83478,26 @@ ${content}</tr>
       context.history().on("change.behaviorHash", _throttledUpdateTitle);
       context.on("enter.behaviorHash", _throttledUpdate);
       select_default2(window).on("hashchange.behaviorHash", hashchange);
-      var q = utilStringQs(window.location.hash);
-      if (q.id) {
-        context.zoomToEntity(q.id.split(",")[0], !q.map);
+      var q2 = utilStringQs(window.location.hash);
+      if (q2.id) {
+        const selectIds = q2.id.split(",");
+        if (selectIds.length === 1 && selectIds[0].startsWith("note/")) {
+          const noteId = selectIds[0].split("/")[1];
+          context.zoomToNote(noteId, !q2.map);
+        } else {
+          context.zoomToEntities(
+            // convert ids to short form id: node/123 -> n123
+            selectIds.map((id2) => id2.replace(/([nwr])[^/]*\//, "$1")),
+            !q2.map
+          );
+        }
       }
-      if (q.walkthrough === "true") {
+      if (q2.walkthrough === "true") {
         behavior.startWalkthrough = true;
       }
-      if (q.map) {
+      if (q2.map) {
         behavior.hadLocation = true;
-      } else if (!q.id && corePreferences("map-location")) {
+      } else if (!q2.id && corePreferences("map-location")) {
         const mapArgs = corePreferences("map-location").split("/").map(Number);
         context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
         updateHashIfNeeded();
@@ -76153,27 +83519,27 @@ ${content}</tr>
 
   // node_modules/d3-brush/src/brush.js
   var { abs: abs2, max: max2, min: min2 } = Math;
-  function number1(e) {
-    return [+e[0], +e[1]];
+  function number1(e3) {
+    return [+e3[0], +e3[1]];
   }
-  function number22(e) {
-    return [number1(e[0]), number1(e[1])];
+  function number22(e3) {
+    return [number1(e3[0]), number1(e3[1])];
   }
-  var X = {
+  var X3 = {
     name: "x",
-    handles: ["w", "e"].map(type2),
-    input: function(x, e) {
-      return x == null ? null : [[+x[0], e[0][1]], [+x[1], e[1][1]]];
+    handles: ["w", "e"].map(type),
+    input: function(x2, e3) {
+      return x2 == null ? null : [[+x2[0], e3[0][1]], [+x2[1], e3[1][1]]];
     },
     output: function(xy) {
       return xy && [xy[0][0], xy[1][0]];
     }
   };
-  var Y = {
+  var Y3 = {
     name: "y",
-    handles: ["n", "s"].map(type2),
-    input: function(y, e) {
-      return y == null ? null : [[e[0][0], +y[0]], [e[1][0], +y[1]]];
+    handles: ["n", "s"].map(type),
+    input: function(y2, e3) {
+      return y2 == null ? null : [[e3[0][0], +y2[0]], [e3[1][0], +y2[1]]];
     },
     output: function(xy) {
       return xy && [xy[0][1], xy[1][1]];
@@ -76181,7 +83547,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,8 +83555,8 @@ ${content}</tr>
       return xy;
     }
   };
-  function type2(t) {
-    return { type: t };
+  function type(t2) {
+    return { type: t2 };
   }
 
   // modules/index.js